From 99980506540d9546dad31223a6eadf126ba68121 Mon Sep 17 00:00:00 2001 From: TTimo <ttimo@ttimo.net> Date: Sun, 4 Nov 2007 03:34:51 +0000 Subject: [PATCH] set eol-style git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant@183 8a3a26a2-13c4-0310-b231-cf6edde360e5 --- Doxygen_files/doxy_mainpage.h | 90 +- contrib/bkgrnd2d/bkgrnd2d.h | 166 +- contrib/bkgrnd2d/dialog.h | 72 +- contrib/bkgrnd2d/plugin.h | 160 +- contrib/bobtoolz/CPortals.h | 126 +- contrib/bobtoolz/DBobView.h | 144 +- contrib/bobtoolz/DBrush.h | 202 +- contrib/bobtoolz/DEPair.h | 90 +- contrib/bobtoolz/DEntity.h | 230 +- contrib/bobtoolz/DListener.h | 124 +- contrib/bobtoolz/DMap.h | 112 +- contrib/bobtoolz/DPatch.h | 124 +- contrib/bobtoolz/DPlane.h | 134 +- contrib/bobtoolz/DPoint.h | 90 +- contrib/bobtoolz/DShape.h | 120 +- contrib/bobtoolz/DTrainDrawer.h | 164 +- contrib/bobtoolz/DTreePlanter.h | 446 +- contrib/bobtoolz/DVisDrawer.h | 116 +- contrib/bobtoolz/DWinding.h | 136 +- contrib/bobtoolz/ScriptParser.h | 82 +- contrib/bobtoolz/StdAfx.h | 308 +- contrib/bobtoolz/bobToolz.h | 128 +- contrib/bobtoolz/bsploader.h | 268 +- contrib/bobtoolz/ctfresource_gtk.h | 68 +- contrib/bobtoolz/dialogs/AboutDialog.h | 128 +- contrib/bobtoolz/dialogs/AutoCaulkDialog.h | 132 +- .../bobtoolz/dialogs/AutoCaulkStartDialog.h | 142 +- contrib/bobtoolz/dialogs/BrushCheckDialog.h | 130 +- contrib/bobtoolz/dialogs/DoorDialog.h | 148 +- contrib/bobtoolz/dialogs/IntersectDialog.h | 140 +- .../bobtoolz/dialogs/IntersectInfoDialog.h | 130 +- contrib/bobtoolz/dialogs/PolygonDialog.h | 148 +- contrib/bobtoolz/dialogs/StairDialog.h | 148 +- contrib/bobtoolz/dialogs/TextureResetDialog.h | 146 +- contrib/bobtoolz/dialogs/dialogs-gtk.h | 196 +- contrib/bobtoolz/dialogs/pathplotterdialog.h | 140 +- contrib/bobtoolz/funchandlers.h | 144 +- contrib/bobtoolz/interfaces/IScriptParser.h | 46 +- contrib/bobtoolz/lists.h | 42 +- contrib/bobtoolz/misc.h | 96 +- contrib/bobtoolz/resource-gtk.h | 30 +- contrib/bobtoolz/resource.h | 230 +- contrib/bobtoolz/shapes.h | 98 +- contrib/bobtoolz/visfind.h | 2 +- contrib/camera/camera.h | 324 +- contrib/camera/dialogs.h | 74 +- contrib/camera/funchandlers.h | 74 +- contrib/camera/listener.h | 128 +- contrib/camera/misc.h | 182 +- contrib/camera/renderer.h | 92 +- contrib/gtkgensurf/gendlgs.h | 302 +- contrib/gtkgensurf/gensurf.h | 790 +- contrib/gtkgensurf/triangle.c | 26472 ++++++++-------- contrib/gtkgensurf/triangle.h | 576 +- contrib/hydratoolz/plugin.h | 102 +- contrib/prtview/AboutDialog.h | 144 +- contrib/prtview/ConfigDialog.h | 214 +- contrib/prtview/LoadPortalFileDialog.h | 154 +- contrib/prtview/gtkdlgs.h | 54 +- contrib/prtview/portals.h | 250 +- contrib/prtview/prtview.h | 58 +- contrib/prtview/resource.h | 84 +- contrib/prtview/stdafx.h | 158 +- docs/developer/XMLPush/StdAfx.h | 44 +- docs/manual/quake3/Compile_Manual/cfgq3.c | 156 +- include/aboutmsg.h | 4 +- include/gtkr_list.h | 46 +- include/gtkr_vector.h | 46 +- include/ibrush.h | 146 +- include/ibspfrontend.h | 154 +- include/icamera.h | 90 +- include/idata.h | 114 +- include/idatastream.h | 142 +- include/ieclass.h | 168 +- include/ientity.h | 232 +- include/ifilesystem.h | 280 +- include/igl.h | 532 +- include/iimage.h | 80 +- include/imap.h | 164 +- include/imodel.h | 212 +- include/ipatch.h | 106 +- include/iplugin.h | 82 +- include/irefcount.h | 124 +- include/iscriplib.h | 172 +- include/iselectedface.h | 176 +- include/ishaders.h | 568 +- include/ishadersmanager.h | 204 +- include/isurfaceplugin.h | 316 +- include/itoolbar.h | 122 +- include/iui.h | 316 +- include/iui_gtk.h | 118 +- include/iundo.h | 174 +- include/misc_def.h | 128 +- include/qerplugin.h | 1574 +- include/qertypes.h | 1822 +- include/qsysprintf.h | 134 +- include/stl_check.h | 120 +- include/stream_version.h | 6 +- include/version.h | 8 +- install/games/default_project.proj | 62 + install/games/{qz.game => q3.game} | 6 +- libs/bytebool.h | 40 +- libs/cmdlib.h | 222 +- libs/ddslib.h | 500 +- libs/ddslib/ddslib.c | 1562 +- libs/igl_to_qgl.h | 1612 +- libs/l_net/l_net.c | 1254 +- libs/l_net/l_net.h | 250 +- libs/l_net/l_net_berkeley.c | 1540 +- libs/l_net/l_net_wins.c | 1578 +- libs/l_net/l_net_wins.h | 104 +- libs/mathlib.h | 610 +- libs/mathlib/bbox.c | 782 +- libs/mathlib/linear.c | 200 +- libs/mathlib/m4x4.c | 1580 +- libs/mathlib/mathlib.c | 1186 +- libs/mathlib/ray.c | 270 +- libs/md5lib.h | 182 +- libs/md5lib/md5lib.c | 790 +- libs/missing.h | 424 +- libs/multimon.h | 760 +- libs/pak/unzip.h | 600 +- libs/pakstuff.h | 300 +- libs/picomodel.h | 690 +- libs/picomodel/lwo/clip.c | 498 +- libs/picomodel/lwo/envelope.c | 1200 +- libs/picomodel/lwo/list.c | 202 +- libs/picomodel/lwo/lwio.c | 884 +- libs/picomodel/lwo/lwo2.c | 616 +- libs/picomodel/lwo/lwo2.h | 1302 +- libs/picomodel/lwo/lwob.c | 1446 +- libs/picomodel/lwo/pntspols.c | 1074 +- libs/picomodel/lwo/surface.c | 2008 +- libs/picomodel/lwo/vecmath.c | 74 +- libs/picomodel/lwo/vmap.c | 486 +- libs/picomodel/picointernal.c | 2706 +- libs/picomodel/picointernal.h | 410 +- libs/picomodel/picomodel.c | 3990 +-- libs/picomodel/picomodules.c | 184 +- libs/picomodel/pm_3ds.c | 1542 +- libs/picomodel/pm_ase.c | 2002 +- libs/picomodel/pm_fm.c | 1340 +- libs/picomodel/pm_fm.h | 734 +- libs/picomodel/pm_lwo.c | 860 +- libs/picomodel/pm_md2.c | 1340 +- libs/picomodel/pm_md3.c | 850 +- libs/picomodel/pm_mdc.c | 1500 +- libs/picomodel/pm_ms3d.c | 988 +- libs/picomodel/pm_obj.c | 1716 +- libs/splines/math_angles.h | 390 +- libs/splines/math_matrix.h | 446 +- libs/splines/math_quaternion.h | 380 +- libs/splines/math_vector.h | 1148 +- libs/splines/q_shared.h | 1592 +- libs/splines/splines.h | 2204 +- libs/splines/util_list.h | 692 +- libs/splines/util_str.h | 1634 +- libs/str.h | 958 +- libs/synapse.h | 1322 +- plugins/eclassfgd/plugin.h | 98 +- plugins/entity/entity.h | 104 +- plugins/entity/entity_entitymodel.h | 300 +- plugins/entity/light.h | 52 +- plugins/entity/plugin.h | 116 +- plugins/image/bmp.h | 202 +- plugins/image/image.h | 136 +- plugins/image/lbmlib.h | 92 +- plugins/imagehl/imagehl.h | 160 +- plugins/imagehl/lbmlib.h | 70 +- plugins/imagem8/imagem8.h | 140 +- plugins/imagem8/m32.h | 128 +- plugins/imagem8/m8.h | 122 +- plugins/imagepng/plugin.h | 62 +- plugins/imagewal/imagewal.h | 120 +- plugins/imagewal/q2_palette.h | 132 +- plugins/imagewal/wal.h | 102 +- plugins/map/plugin.h | 184 +- plugins/mapxml/plugin.h | 98 +- plugins/model/cpicomodel.h | 188 +- plugins/model/cpicosurface.h | 110 +- plugins/model/plugin.h | 152 +- plugins/model/surface.h | 74 +- plugins/shaders/plugin.h | 138 +- plugins/shaders/shaders.h | 334 +- plugins/spritemodel/plugin.h | 156 +- plugins/spritemodel/spritemodel.h | 114 +- plugins/surface/surfacedialog.h | 62 +- plugins/surface/surfdlg_plugin.h | 188 +- plugins/surface_heretic2/surfacedialog.h | 62 +- .../surfaceflagsdialog_heretic2.h | 152 +- plugins/surface_heretic2/surfdlg_plugin.h | 188 +- plugins/surface_quake2/surfacedialog.h | 62 +- .../surfaceflagsdialog_quake2.h | 216 +- plugins/surface_quake2/surfdlg_plugin.h | 188 +- plugins/textool/2DView.h | 140 +- plugins/textool/ControlPointsManager.h | 266 +- plugins/textool/StdAfx.h | 308 +- plugins/textool/resource.h | 46 +- plugins/vfspak/vfs.h | 104 +- plugins/vfspak/vfspak.h | 128 +- plugins/vfspk3/unzip-vfspk3.h | 598 +- plugins/vfspk3/vfs.h | 136 +- plugins/vfspk3/vfspk3.h | 126 +- plugins/vfswad/unwad.h | 222 +- plugins/vfswad/vfs.h | 138 +- plugins/vfswad/vfswad.h | 126 +- radiant/brush.h | 178 +- radiant/camera.h | 166 +- radiant/camwindow.h | 342 +- radiant/dialog.h | 170 +- radiant/eclass_def.h | 88 +- radiant/feedback.h | 250 +- radiant/file.h | 238 +- radiant/filters.h | 60 +- radiant/findtexturedialog.h | 98 +- radiant/glwidget.h | 90 +- radiant/glwindow.h | 216 +- radiant/groupdialog.h | 216 +- radiant/gtkfilesel-darwin.c | 6720 ++-- radiant/gtkfilesel-darwin.h | 258 +- radiant/gtkfilesel-linux.c | 9974 +++--- radiant/gtkfilesel-linux.h | 286 +- radiant/gtkfilesel.c | 6674 ++-- radiant/gtkfilesel.h | 286 +- radiant/gtkmisc.h | 200 +- radiant/mainframe.h | 1818 +- radiant/map.h | 144 +- radiant/parse.h | 70 +- radiant/patchdialog.h | 170 +- radiant/plugin.h | 90 +- radiant/pluginmanager.h | 424 +- radiant/points.h | 114 +- radiant/preferences.h | 1256 +- radiant/qe3.h | 1824 +- radiant/qedefs.h | 256 +- radiant/qfiles.h | 960 +- radiant/qgl-mac.c | 3550 +-- radiant/qgl.c | 3594 +-- radiant/qgl.h | 1200 +- radiant/resource.h | 74 +- radiant/select.h | 164 +- radiant/stdafx.h | 78 +- radiant/surfacedialog.h | 138 +- radiant/surfaceplugin.h | 22 +- radiant/texmanip.h | 78 +- radiant/textures.h | 104 +- radiant/texwindow.h | 124 +- radiant/ui.h | 168 +- radiant/undo.h | 132 +- radiant/watchbsp.h | 182 +- radiant/winding.h | 140 +- radiant/xmlstuff.h | 140 +- radiant/xywindow.h | 388 +- radiant/z.h | 84 +- radiant/zwindow.h | 92 +- tools/quake2/common/bspfile.c | 1578 +- tools/quake2/common/bspfile.h | 256 +- tools/quake2/common/cmdlib.c | 2442 +- tools/quake2/common/cmdlib.h | 340 +- tools/quake2/common/inout.c | 734 +- tools/quake2/common/inout.h | 126 +- tools/quake2/common/l3dslib.c | 600 +- tools/quake2/common/l3dslib.h | 50 +- tools/quake2/common/lbmlib.c | 1674 +- tools/quake2/common/lbmlib.h | 76 +- tools/quake2/common/mathlib.c | 344 +- tools/quake2/common/mathlib.h | 150 +- tools/quake2/common/path_init.c | 800 +- tools/quake2/common/polylib.c | 1284 +- tools/quake2/common/polylib.h | 108 +- tools/quake2/common/q2_threads.h | 68 +- tools/quake2/common/qfiles.h | 1126 +- tools/quake2/common/scriplib.c | 592 +- tools/quake2/common/scriplib.h | 86 +- tools/quake2/common/threads.c | 1244 +- tools/quake2/common/trilib.c | 372 +- tools/quake2/common/trilib.h | 62 +- tools/quake2/q2map/brushbsp.c | 2658 +- tools/quake2/q2map/csg.c | 1268 +- tools/quake2/q2map/faces.c | 2152 +- tools/quake2/q2map/flow.c | 1574 +- tools/quake2/q2map/gldraw.c | 462 +- tools/quake2/q2map/glfile.c | 296 +- tools/quake2/q2map/leakfile.c | 360 +- tools/quake2/q2map/lightmap.c | 2630 +- tools/quake2/q2map/main.c | 1442 +- tools/quake2/q2map/map.c | 2034 +- tools/quake2/q2map/nodraw.c | 92 +- tools/quake2/q2map/patches.c | 1206 +- tools/quake2/q2map/portals.c | 2220 +- tools/quake2/q2map/prtfile.c | 572 +- tools/quake2/q2map/q2map.h | 100 +- tools/quake2/q2map/qbsp.c | 852 +- tools/quake2/q2map/qbsp.h | 780 +- tools/quake2/q2map/qrad.c | 1294 +- tools/quake2/q2map/qrad.h | 368 +- tools/quake2/q2map/qvis.c | 1162 +- tools/quake2/q2map/qvis.h | 338 +- tools/quake2/q2map/textures.c | 498 +- tools/quake2/q2map/trace.c | 596 +- tools/quake2/q2map/tree.c | 436 +- tools/quake2/q2map/writebsp.c | 1182 +- tools/quake2/qdata/anorms.h | 324 +- tools/quake2/qdata/images.c | 1484 +- tools/quake2/qdata/models.c | 2264 +- tools/quake2/qdata/qdata.c | 1052 +- tools/quake2/qdata/qdata.h | 150 +- tools/quake2/qdata/sprites.c | 416 +- tools/quake2/qdata/tables.c | 300 +- tools/quake2/qdata/video.c | 2476 +- tools/quake2/qdata_heretic2/adpcm.h | 98 +- tools/quake2/qdata_heretic2/animcomp.c | 702 +- tools/quake2/qdata_heretic2/animcomp.h | 86 +- tools/quake2/qdata_heretic2/anorms.h | 364 +- tools/quake2/qdata_heretic2/book.c | 744 +- tools/quake2/qdata_heretic2/common/bspfile.c | 1586 +- tools/quake2/qdata_heretic2/common/bspfile.h | 266 +- tools/quake2/qdata_heretic2/common/cmdlib.c | 2476 +- tools/quake2/qdata_heretic2/common/cmdlib.h | 354 +- .../qdata_heretic2/common/her2_threads.h | 70 +- tools/quake2/qdata_heretic2/common/inout.c | 734 +- tools/quake2/qdata_heretic2/common/inout.h | 126 +- tools/quake2/qdata_heretic2/common/l3dslib.c | 952 +- tools/quake2/qdata_heretic2/common/l3dslib.h | 56 +- tools/quake2/qdata_heretic2/common/lbmlib.c | 2104 +- tools/quake2/qdata_heretic2/common/lbmlib.h | 82 +- tools/quake2/qdata_heretic2/common/mathlib.c | 352 +- tools/quake2/qdata_heretic2/common/mathlib.h | 152 +- .../quake2/qdata_heretic2/common/path_init.c | 808 +- tools/quake2/qdata_heretic2/common/polylib.c | 1312 +- tools/quake2/qdata_heretic2/common/polylib.h | 110 +- tools/quake2/qdata_heretic2/common/qfiles.c | 164 +- tools/quake2/qdata_heretic2/common/qfiles.h | 1238 +- tools/quake2/qdata_heretic2/common/scriplib.c | 594 +- tools/quake2/qdata_heretic2/common/scriplib.h | 88 +- tools/quake2/qdata_heretic2/common/threads.c | 1240 +- tools/quake2/qdata_heretic2/common/token.c | 1100 +- tools/quake2/qdata_heretic2/common/token.h | 264 +- tools/quake2/qdata_heretic2/common/trilib.c | 2154 +- tools/quake2/qdata_heretic2/common/trilib.h | 112 +- tools/quake2/qdata_heretic2/fmodels.c | 6808 ++-- tools/quake2/qdata_heretic2/images.c | 2794 +- tools/quake2/qdata_heretic2/jointed.c | 1144 +- tools/quake2/qdata_heretic2/jointed.h | 70 +- tools/quake2/qdata_heretic2/joints.h | 288 +- tools/quake2/qdata_heretic2/models.c | 4100 +-- tools/quake2/qdata_heretic2/pics.c | 396 +- tools/quake2/qdata_heretic2/qcommon/angles.h | 152 +- .../qdata_heretic2/qcommon/arrayedlist.h | 142 +- tools/quake2/qdata_heretic2/qcommon/flex.h | 66 +- tools/quake2/qdata_heretic2/qcommon/fmodel.h | 404 +- .../quake2/qdata_heretic2/qcommon/h2common.h | 52 +- .../quake2/qdata_heretic2/qcommon/placement.h | 76 +- .../quake2/qdata_heretic2/qcommon/q_typedef.h | 126 +- tools/quake2/qdata_heretic2/qcommon/qfiles.h | 1208 +- .../quake2/qdata_heretic2/qcommon/reference.c | 248 +- .../quake2/qdata_heretic2/qcommon/reference.h | 252 +- .../qdata_heretic2/qcommon/resourcemanager.c | 318 +- .../qdata_heretic2/qcommon/resourcemanager.h | 94 +- .../quake2/qdata_heretic2/qcommon/skeletons.c | 464 +- .../quake2/qdata_heretic2/qcommon/skeletons.h | 214 +- tools/quake2/qdata_heretic2/qd_fmodel.h | 122 +- tools/quake2/qdata_heretic2/qd_skeletons.c | 2582 +- tools/quake2/qdata_heretic2/qd_skeletons.h | 168 +- tools/quake2/qdata_heretic2/qdata.c | 1460 +- tools/quake2/qdata_heretic2/qdata.h | 332 +- tools/quake2/qdata_heretic2/resource.h | 36 +- tools/quake2/qdata_heretic2/sprites.c | 698 +- tools/quake2/qdata_heretic2/svdcmp.c | 980 +- tools/quake2/qdata_heretic2/tables.c | 342 +- tools/quake2/qdata_heretic2/tmix.c | 1396 +- tools/quake2/qdata_heretic2/video.c | 2298 +- tools/quake3/common/aselib.c | 1930 +- tools/quake3/common/aselib.h | 62 +- tools/quake3/common/bspfile.c | 1412 +- tools/quake3/common/bspfile.h | 242 +- tools/quake3/common/cmdlib.c | 2306 +- tools/quake3/common/cmdlib.h | 320 +- tools/quake3/common/imagelib.c | 2440 +- tools/quake3/common/imagelib.h | 88 +- tools/quake3/common/inout.c | 734 +- tools/quake3/common/inout.h | 122 +- tools/quake3/common/l3dslib.c | 602 +- tools/quake3/common/l3dslib.h | 52 +- tools/quake3/common/mutex.c | 394 +- tools/quake3/common/mutex.h | 56 +- tools/quake3/common/polylib.c | 1490 +- tools/quake3/common/polylib.h | 114 +- tools/quake3/common/polyset.h | 102 +- tools/quake3/common/qfiles.h | 978 +- tools/quake3/common/qthreads.h | 62 +- tools/quake3/common/scriplib.c | 818 +- tools/quake3/common/scriplib.h | 110 +- tools/quake3/common/surfaceflags.h | 224 +- tools/quake3/common/threads.c | 1240 +- tools/quake3/common/trilib.c | 470 +- tools/quake3/common/trilib.h | 52 +- tools/quake3/common/unzip.c | 9192 +++--- tools/quake3/common/unzip.h | 642 +- tools/quake3/common/vfs.c | 730 +- tools/quake3/common/vfs.h | 82 +- tools/quake3/q3data/3dslib.c | 1260 +- tools/quake3/q3data/3dslib.h | 236 +- tools/quake3/q3data/compress.c | 1500 +- tools/quake3/q3data/images.c | 930 +- tools/quake3/q3data/md3lib.c | 386 +- tools/quake3/q3data/md3lib.h | 14 +- tools/quake3/q3data/models.c | 4268 +-- tools/quake3/q3data/oldstuff.c | 260 +- tools/quake3/q3data/p3dlib.c | 648 +- tools/quake3/q3data/p3dlib.h | 16 +- tools/quake3/q3data/polyset.c | 504 +- tools/quake3/q3data/q3data.c | 1286 +- tools/quake3/q3data/q3data.h | 156 +- tools/quake3/q3data/stripper.c | 564 +- tools/quake3/q3data/video.c | 2264 +- tools/quake3/q3map2/brush.c | 1964 +- tools/quake3/q3map2/brush_primit.c | 160 +- tools/quake3/q3map2/bsp.c | 1706 +- tools/quake3/q3map2/bspfile_abstract.c | 1668 +- tools/quake3/q3map2/bspfile_ibsp.c | 1168 +- tools/quake3/q3map2/bspfile_rbsp.c | 678 +- tools/quake3/q3map2/convert_ase.c | 748 +- tools/quake3/q3map2/convert_map.c | 886 +- tools/quake3/q3map2/decals.c | 1816 +- tools/quake3/q3map2/facebsp.c | 906 +- tools/quake3/q3map2/fog.c | 1608 +- tools/quake3/q3map2/game_ef.h | 372 +- tools/quake3/q3map2/game_ja.h | 360 +- tools/quake3/q3map2/game_jk2.h | 348 +- tools/quake3/q3map2/game_quake3.h | 368 +- tools/quake3/q3map2/game_sof2.h | 498 +- tools/quake3/q3map2/game_t.h | 68 +- tools/quake3/q3map2/game_tenebrae.h | 368 +- tools/quake3/q3map2/game_wolf.h | 460 +- tools/quake3/q3map2/game_wolfet.h | 338 +- tools/quake3/q3map2/image.c | 934 +- tools/quake3/q3map2/leakfile.c | 252 +- tools/quake3/q3map2/light.c | 4364 +-- tools/quake3/q3map2/light_bounce.c | 1908 +- tools/quake3/q3map2/light_shadows.c | 246 +- tools/quake3/q3map2/light_trace.c | 3508 +- tools/quake3/q3map2/light_ydnar.c | 6258 ++-- tools/quake3/q3map2/lightmaps.c | 992 +- tools/quake3/q3map2/lightmaps_ydnar.c | 5994 ++-- tools/quake3/q3map2/main.c | 912 +- tools/quake3/q3map2/map.c | 3298 +- tools/quake3/q3map2/mesh.c | 1650 +- tools/quake3/q3map2/model.c | 1412 +- tools/quake3/q3map2/patch.c | 1048 +- tools/quake3/q3map2/path_init.c | 912 +- tools/quake3/q3map2/portals.c | 1940 +- tools/quake3/q3map2/prtfile.c | 582 +- tools/quake3/q3map2/q3map2.h | 4552 +-- tools/quake3/q3map2/shaders.c | 3852 +-- tools/quake3/q3map2/surface.c | 7066 ++--- tools/quake3/q3map2/surface_extra.c | 888 +- tools/quake3/q3map2/surface_foliage.c | 654 +- tools/quake3/q3map2/surface_fur.c | 256 +- tools/quake3/q3map2/surface_meta.c | 3252 +- tools/quake3/q3map2/tjunction.c | 1454 +- tools/quake3/q3map2/tree.c | 316 +- tools/quake3/q3map2/vis.c | 2244 +- tools/quake3/q3map2/visflow.c | 3418 +- tools/quake3/q3map2/writebsp.c | 1292 +- 465 files changed, 188554 insertions(+), 188492 deletions(-) create mode 100644 install/games/default_project.proj rename install/games/{qz.game => q3.game} (57%) diff --git a/Doxygen_files/doxy_mainpage.h b/Doxygen_files/doxy_mainpage.h index 34e4bc50..34b43d9d 100644 --- a/Doxygen_files/doxy_mainpage.h +++ b/Doxygen_files/doxy_mainpage.h @@ -1,45 +1,45 @@ -/* -** Doxygen index.html generation file -** -*/ - -/*! \mainpage +project+ Doxygen Index - <img src="../images/gtkr_splash.jpg" align="right" hspace="2" vspace="2"> - \section intro Introduction - - This documentation was generated from GtkRadiant source code using Doxygen.<br> - Generated from source in: +target+ - - \section links Links - <b>General Links</b><br> - <a href="http://www.doxygen.org">Doxygen Homepage</a><br> - <a href="http://www.gtkradiant.com">GtkRadiant Homepage</a><br> - <a href="http://zerowing.idsoftare.com">Zerowing - GtkRadiant Development</a><br> - - <b>Local Links</b><br> - <a href="../reference/index.html">Doxygen Quick Reference (Local)</a><br> - - <p> - <b>GtkRadiant FAQ Links</b><br> - <a href="http://www.qeradiant.com/faq/fom-serve/cache/115.html">GtkRadiant FAQ</a><br> - <a href="http://www.qeradiant.com/faq/fom-serve/cache/181.html">GtkRadiant FAQ: Open Tasks</a><br> - <a href="http://www.qeradiant.com/faq/fom-serve/cache/116.html">GtkRadiant FAQ: Compiling instructions</a><br> - <a href="http://www.qeradiant.com/faq/fom-serve/cache/116.html">GtkRadiant FAQ: Creating/Submitting patches</a><br> - <a href="http://www.qeradiant.com/faq/fom-serve/cache/141.html">GtkRadiant FAQ: Coding Conventions & Guidelines</a><br> - </p> - - <b>Misc Links</b><br> - <a href="http://www.idsoftware.com">idsoftware.com</a><br> - - <p> - <i> - * Note: The content on this page was generated from <a href="doxy__mainpage_8h.html">this</A> file. - It is moved into the <target> path when the doxygen documentation is generated, and removed immediately - afterwards. - </i> - </p> - - <i>This page generated: by <b>+user+</b> on <b>+machine+</b><br> - On +date+ - </i> -*/ +/* +** Doxygen index.html generation file +** +*/ + +/*! \mainpage +project+ Doxygen Index + <img src="../images/gtkr_splash.jpg" align="right" hspace="2" vspace="2"> + \section intro Introduction + + This documentation was generated from GtkRadiant source code using Doxygen.<br> + Generated from source in: +target+ + + \section links Links + <b>General Links</b><br> + <a href="http://www.doxygen.org">Doxygen Homepage</a><br> + <a href="http://www.gtkradiant.com">GtkRadiant Homepage</a><br> + <a href="http://zerowing.idsoftare.com">Zerowing - GtkRadiant Development</a><br> + + <b>Local Links</b><br> + <a href="../reference/index.html">Doxygen Quick Reference (Local)</a><br> + + <p> + <b>GtkRadiant FAQ Links</b><br> + <a href="http://www.qeradiant.com/faq/fom-serve/cache/115.html">GtkRadiant FAQ</a><br> + <a href="http://www.qeradiant.com/faq/fom-serve/cache/181.html">GtkRadiant FAQ: Open Tasks</a><br> + <a href="http://www.qeradiant.com/faq/fom-serve/cache/116.html">GtkRadiant FAQ: Compiling instructions</a><br> + <a href="http://www.qeradiant.com/faq/fom-serve/cache/116.html">GtkRadiant FAQ: Creating/Submitting patches</a><br> + <a href="http://www.qeradiant.com/faq/fom-serve/cache/141.html">GtkRadiant FAQ: Coding Conventions & Guidelines</a><br> + </p> + + <b>Misc Links</b><br> + <a href="http://www.idsoftware.com">idsoftware.com</a><br> + + <p> + <i> + * Note: The content on this page was generated from <a href="doxy__mainpage_8h.html">this</A> file. + It is moved into the <target> path when the doxygen documentation is generated, and removed immediately + afterwards. + </i> + </p> + + <i>This page generated: by <b>+user+</b> on <b>+machine+</b><br> + On +date+ + </i> +*/ diff --git a/contrib/bkgrnd2d/bkgrnd2d.h b/contrib/bkgrnd2d/bkgrnd2d.h index bee6e811..bf4771bb 100644 --- a/contrib/bkgrnd2d/bkgrnd2d.h +++ b/contrib/bkgrnd2d/bkgrnd2d.h @@ -1,83 +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; - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/dialog.h b/contrib/bkgrnd2d/dialog.h index 7a82cdd6..b6d80430 100644 --- a/contrib/bkgrnd2d/dialog.h +++ b/contrib/bkgrnd2d/dialog.h @@ -1,36 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/contrib/bkgrnd2d/plugin.h index 84933ae0..15fe7d62 100644 --- a/contrib/bkgrnd2d/plugin.h +++ b/contrib/bkgrnd2d/plugin.h @@ -1,80 +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 <stdio.h> -// 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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +// 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/bobtoolz/CPortals.h b/contrib/bobtoolz/CPortals.h index bc9d16ac..60506be8 100644 --- a/contrib/bobtoolz/CPortals.h +++ b/contrib/bobtoolz/CPortals.h @@ -1,63 +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; -}; +/* +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.h b/contrib/bobtoolz/DBobView.h index 4259c97a..94902607 100644 --- a/contrib/bobtoolz/DBobView.h +++ b/contrib/bobtoolz/DBobView.h @@ -1,72 +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_) +/* +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.h b/contrib/bobtoolz/DBrush.h index 7f2485cd..65013dcc 100644 --- a/contrib/bobtoolz/DBrush.h +++ b/contrib/bobtoolz/DBrush.h @@ -1,101 +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<Str>* 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<DPlane*> faceList; - list<DPoint*> pointList; - int m_nBrushID; - vec3_t bbox_min, bbox_max; - bool bBoundsBuilt; -}; - -//typedef CList<DBrush*, DBrush*> DBrushList; - -#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +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<Str>* 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<DPlane*> faceList; + list<DPoint*> pointList; + int m_nBrushID; + vec3_t bbox_min, bbox_max; + bool bBoundsBuilt; +}; + +//typedef CList<DBrush*, DBrush*> DBrushList; + +#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEPair.h b/contrib/bobtoolz/DEPair.h index e5438af4..11f79045 100644 --- a/contrib/bobtoolz/DEPair.h +++ b/contrib/bobtoolz/DEPair.h @@ -1,45 +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<DEPair*, DEPair*> DEPairList; - -#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +/* +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<DEPair*, DEPair*> DEPairList; + +#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEntity.h b/contrib/bobtoolz/DEntity.h index 382e8a0f..63837c84 100644 --- a/contrib/bobtoolz/DEntity.h +++ b/contrib/bobtoolz/DEntity.h @@ -1,115 +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<Str>* exclusionList); - void RemoveNonCheckBrushes(list<Str>* 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<DEPair*> epairList; - list<DBrush*> brushList; - // new patches, wahey!!! - list<DPatch*> 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_) +/* +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<Str>* exclusionList); + void RemoveNonCheckBrushes(list<Str>* 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<DEPair*> epairList; + list<DBrush*> brushList; + // new patches, wahey!!! + list<DPatch*> 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.h b/contrib/bobtoolz/DListener.h index 0ef20577..d2166993 100644 --- a/contrib/bobtoolz/DListener.h +++ b/contrib/bobtoolz/DListener.h @@ -1,62 +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_) +/* +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.h b/contrib/bobtoolz/DMap.h index 1f814c23..2d572114 100644 --- a/contrib/bobtoolz/DMap.h +++ b/contrib/bobtoolz/DMap.h @@ -1,56 +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<DEntity*> entityList; - - DMap(); - virtual ~DMap(); - - int FixBrushes(bool rebuild); -}; - -#endif // !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) +/* +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<DEntity*> 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.h b/contrib/bobtoolz/DPatch.h index d04121ea..6bdf8e60 100644 --- a/contrib/bobtoolz/DPatch.h +++ b/contrib/bobtoolz/DPatch.h @@ -1,62 +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<DPatch> 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_) +/* +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<DPatch> 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.h b/contrib/bobtoolz/DPlane.h index 4399b841..f1a84319 100644 --- a/contrib/bobtoolz/DPlane.h +++ b/contrib/bobtoolz/DPlane.h @@ -1,67 +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<DPoint*>& 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<DPlane*, DPlane*> DPlaneList; -#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +/* +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<DPoint*>& 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<DPlane*, DPlane*> DPlaneList; +#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DPoint.h b/contrib/bobtoolz/DPoint.h index 22ae70bc..394352cf 100644 --- a/contrib/bobtoolz/DPoint.h +++ b/contrib/bobtoolz/DPoint.h @@ -1,45 +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<DPoint*, DPoint*> DPointList; - -#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +/* +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<DPoint*, DPoint*> DPointList; + +#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DShape.h b/contrib/bobtoolz/DShape.h index 9564943d..4bc4baa8 100644 --- a/contrib/bobtoolz/DShape.h +++ b/contrib/bobtoolz/DShape.h @@ -1,60 +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_) +/* +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.h b/contrib/bobtoolz/DTrainDrawer.h index 5f424068..3c7ac779 100644 --- a/contrib/bobtoolz/DTrainDrawer.h +++ b/contrib/bobtoolz/DTrainDrawer.h @@ -1,82 +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<controlPoint_t> m_pointList; - list<DPoint> m_vertexList; - - controlPoint_t* pTarget; -} splinePoint_t; - -class DTrainDrawer : - public IGL2DWindow, - public IGL3DWindow -{ -private: - list<splinePoint_t*> m_splineList; - list<controlPoint_t*> 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_) +/* +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<controlPoint_t> m_pointList; + list<DPoint> m_vertexList; + + controlPoint_t* pTarget; +} splinePoint_t; + +class DTrainDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +private: + list<splinePoint_t*> m_splineList; + list<controlPoint_t*> 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.h b/contrib/bobtoolz/DTreePlanter.h index ab80abff..9048e60b 100644 --- a/contrib/bobtoolz/DTreePlanter.h +++ b/contrib/bobtoolz/DTreePlanter.h @@ -1,223 +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 +/* +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.h b/contrib/bobtoolz/DVisDrawer.h index c0ba1aa9..2f9ac315 100644 --- a/contrib/bobtoolz/DVisDrawer.h +++ b/contrib/bobtoolz/DVisDrawer.h @@ -1,58 +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<DWinding*>* m_list; - int refCount; -public: - void ClearPoints(); - void SetList(list<DWinding*>* 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_) +/* +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<DWinding*>* m_list; + int refCount; +public: + void ClearPoints(); + void SetList(list<DWinding*>* 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.h b/contrib/bobtoolz/DWinding.h index d173fbf6..6d58e06e 100644 --- a/contrib/bobtoolz/DWinding.h +++ b/contrib/bobtoolz/DWinding.h @@ -1,68 +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_) +/* +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.h b/contrib/bobtoolz/ScriptParser.h index 60c92f51..5537401f 100644 --- a/contrib/bobtoolz/ScriptParser.h +++ b/contrib/bobtoolz/ScriptParser.h @@ -1,41 +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 + +#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.h b/contrib/bobtoolz/StdAfx.h index 88183232..195e3d85 100644 --- a/contrib/bobtoolz/StdAfx.h +++ b/contrib/bobtoolz/StdAfx.h @@ -1,154 +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 <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> -#include <stdio.h> -#include <stdlib.h> - -#include "time.h" - -#if defined (__linux__) || defined (__APPLE__) - -// Necessary for proper boolean type declaration -#include "qertypes.h" - -#include <GL/glx.h> - -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 +/* +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 <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <stdio.h> +#include <stdlib.h> + +#include "time.h" + +#if defined (__linux__) || defined (__APPLE__) + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +#include <GL/glx.h> + +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/bobToolz.h b/contrib/bobtoolz/bobToolz.h index d4290099..6101e877 100644 --- a/contrib/bobtoolz/bobToolz.h +++ b/contrib/bobtoolz/bobToolz.h @@ -1,64 +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_) +/* +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/bsploader.h b/contrib/bobtoolz/bsploader.h index 96f7c851..3b98fc27 100644 --- a/contrib/bobtoolz/bsploader.h +++ b/contrib/bobtoolz/bsploader.h @@ -1,134 +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(); +#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/ctfresource_gtk.h b/contrib/bobtoolz/ctfresource_gtk.h index e0d51870..3f706a04 100644 --- a/contrib/bobtoolz/ctfresource_gtk.h +++ b/contrib/bobtoolz/ctfresource_gtk.h @@ -1,34 +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 +/* +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/dialogs/AboutDialog.h b/contrib/bobtoolz/dialogs/AboutDialog.h index 6467b4a6..54cfd017 100644 --- a/contrib/bobtoolz/dialogs/AboutDialog.h +++ b/contrib/bobtoolz/dialogs/AboutDialog.h @@ -1,64 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h index 313a547b..a8740275 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkDialog.h +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h @@ -1,66 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h index 753b068c..9311c51c 100644 --- a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h @@ -1,71 +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_) +/* +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 index 776c6137..2ccf8e8f 100644 --- a/contrib/bobtoolz/dialogs/BrushCheckDialog.h +++ b/contrib/bobtoolz/dialogs/BrushCheckDialog.h @@ -1,65 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/DoorDialog.h index a40fd5b6..4d312cb9 100644 --- a/contrib/bobtoolz/dialogs/DoorDialog.h +++ b/contrib/bobtoolz/dialogs/DoorDialog.h @@ -1,74 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/IntersectDialog.h index 79a6e3cb..d1190a6f 100644 --- a/contrib/bobtoolz/dialogs/IntersectDialog.h +++ b/contrib/bobtoolz/dialogs/IntersectDialog.h @@ -1,70 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h index 72709ab3..51a4bf75 100644 --- a/contrib/bobtoolz/dialogs/IntersectInfoDialog.h +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h @@ -1,65 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/PolygonDialog.h index d556f500..afe5cb87 100644 --- a/contrib/bobtoolz/dialogs/PolygonDialog.h +++ b/contrib/bobtoolz/dialogs/PolygonDialog.h @@ -1,74 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/StairDialog.h index c42959af..0bcdc0ec 100644 --- a/contrib/bobtoolz/dialogs/StairDialog.h +++ b/contrib/bobtoolz/dialogs/StairDialog.h @@ -1,74 +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_) +/* +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.h b/contrib/bobtoolz/dialogs/TextureResetDialog.h index e0843505..6f041611 100644 --- a/contrib/bobtoolz/dialogs/TextureResetDialog.h +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.h @@ -1,73 +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_) +/* +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/dialogs-gtk.h b/contrib/bobtoolz/dialogs/dialogs-gtk.h index 589b994e..987f7216 100644 --- a/contrib/bobtoolz/dialogs/dialogs-gtk.h +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.h @@ -1,98 +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); +/* +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.h b/contrib/bobtoolz/dialogs/pathplotterdialog.h index 749e4da3..6edd8987 100644 --- a/contrib/bobtoolz/dialogs/pathplotterdialog.h +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.h @@ -1,70 +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_) +/* +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.h b/contrib/bobtoolz/funchandlers.h index d8c1e33c..1e3696cb 100644 --- a/contrib/bobtoolz/funchandlers.h +++ b/contrib/bobtoolz/funchandlers.h @@ -1,72 +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 ); +/* +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 index 934a9671..5d0ee5ba 100644 --- a/contrib/bobtoolz/interfaces/IScriptParser.h +++ b/contrib/bobtoolz/interfaces/IScriptParser.h @@ -1,23 +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 +#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.h b/contrib/bobtoolz/lists.h index d71e7594..6f9774f6 100644 --- a/contrib/bobtoolz/lists.h +++ b/contrib/bobtoolz/lists.h @@ -1,21 +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<Str>* exclusionList); -bool LoadGList(char* filename, GList** loadlist); +/* +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<Str>* exclusionList); +bool LoadGList(char* filename, GList** loadlist); diff --git a/contrib/bobtoolz/misc.h b/contrib/bobtoolz/misc.h index c02a99e9..81b48879 100644 --- a/contrib/bobtoolz/misc.h +++ b/contrib/bobtoolz/misc.h @@ -1,48 +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<Str>* 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 ); +/* +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<Str>* 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/resource-gtk.h b/contrib/bobtoolz/resource-gtk.h index e4522dff..9297877f 100644 --- a/contrib/bobtoolz/resource-gtk.h +++ b/contrib/bobtoolz/resource-gtk.h @@ -1,15 +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 +//{{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 index 999d639b..2c7f97ed 100644 --- a/contrib/bobtoolz/resource.h +++ b/contrib/bobtoolz/resource.h @@ -1,115 +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 +/* +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.h b/contrib/bobtoolz/shapes.h index e5fccd9c..46eae37a 100644 --- a/contrib/bobtoolz/shapes.h +++ b/contrib/bobtoolz/shapes.h @@ -1,49 +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. +/* +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/visfind.h b/contrib/bobtoolz/visfind.h index 732f3b6c..0a4b601e 100644 --- a/contrib/bobtoolz/visfind.h +++ b/contrib/bobtoolz/visfind.h @@ -1 +1 @@ -list<DWinding*> *BuildTrace(char* filename, vec3_t v_origin); +list<DWinding*> *BuildTrace(char* filename, vec3_t v_origin); diff --git a/contrib/camera/camera.h b/contrib/camera/camera.h index d60783a9..cf1387c2 100644 --- a/contrib/camera/camera.h +++ b/contrib/camera/camera.h @@ -1,162 +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 <gtk/gtk.h> - -#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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <gtk/gtk.h> + +#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/dialogs.h b/contrib/camera/dialogs.h index 5ba86c5a..93dbce1d 100644 --- a/contrib/camera/dialogs.h +++ b/contrib/camera/dialogs.h @@ -1,37 +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 ); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/funchandlers.h b/contrib/camera/funchandlers.h index a9419062..ee3b9274 100644 --- a/contrib/camera/funchandlers.h +++ b/contrib/camera/funchandlers.h @@ -1,37 +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 ); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/contrib/camera/listener.h index 13e14b71..6519508f 100644 --- a/contrib/camera/listener.h +++ b/contrib/camera/listener.h @@ -1,64 +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; -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/contrib/camera/misc.h index 6c56dc73..52062c88 100644 --- a/contrib/camera/misc.h +++ b/contrib/camera/misc.h @@ -1,91 +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];} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/contrib/camera/renderer.h index c2ca93bd..989567a1 100644 --- a/contrib/camera/renderer.h +++ b/contrib/camera/renderer.h @@ -1,46 +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; -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/gendlgs.h b/contrib/gtkgensurf/gendlgs.h index c6df4866..dd954678 100644 --- a/contrib/gtkgensurf/gendlgs.h +++ b/contrib/gtkgensurf/gendlgs.h @@ -1,151 +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 +/* +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/gensurf.h b/contrib/gtkgensurf/gensurf.h index 2c516d4e..8e42ac0d 100644 --- a/contrib/gtkgensurf/gensurf.h +++ b/contrib/gtkgensurf/gensurf.h @@ -1,395 +1,395 @@ -/* -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 -*/ - -#ifndef _GENSURF_H_ -#define _GENSURF_H_ - -#include <gtk/gtk.h> - -#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 <class T> -inline T min (T x, T y) { return (x < y) ? x : y; } -template <class T> -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_ +/* +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 +*/ + +#ifndef _GENSURF_H_ +#define _GENSURF_H_ + +#include <gtk/gtk.h> + +#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 <class T> +inline T min (T x, T y) { return (x < y) ? x : y; } +template <class T> +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/triangle.c b/contrib/gtkgensurf/triangle.c index 1462499f..1e155cac 100644 --- a/contrib/gtkgensurf/triangle.c +++ b/contrib/gtkgensurf/triangle.c @@ -1,13236 +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 <stdio.h> -#include <string.h> -#include <math.h> -#ifndef NO_TIMER -#include <sys/time.h> -#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> <dimension (must be 2)> <# of attributes>\n"); - printf( -" <# of boundary markers (0 or 1)>\n" -); - printf( -" Remaining lines: <point #> <x> <y> [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> <points per triangle> <# of attributes>\n"); - printf( -" Remaining lines: <triangle #> <point> <point> <point> ... [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> <dimension (must be 2)> <# of attributes>\n"); - printf( -" <# of boundary markers (0 or 1)>\n" -); - printf( -" Following lines: <point #> <x> <y> [attributes] [boundary marker]\n"); - printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); - printf( -" Following lines: <segment #> <endpoint> <endpoint> [boundary marker]\n"); - printf(" One line: <# of holes>\n"); - printf(" Following lines: <hole #> <x> <y>\n"); - printf( -" Optional line: <# of regional attributes and/or area constraints>\n"); - printf( -" Optional following lines: <constraint #> <x> <y> <attrib> <max area>\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: <triangle #> <maximum area>\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: <edge #> <endpoint> <endpoint> [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(" <edge #> <endpoint> -1 <direction x> <direction y>\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: <triangle #> <neighbor> <neighbor> <neighbor>\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 */ -} +#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 <stdio.h> +#include <string.h> +#include <math.h> +#ifndef NO_TIMER +#include <sys/time.h> +#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> <dimension (must be 2)> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Remaining lines: <point #> <x> <y> [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> <points per triangle> <# of attributes>\n"); + printf( +" Remaining lines: <triangle #> <point> <point> <point> ... [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> <dimension (must be 2)> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Following lines: <point #> <x> <y> [attributes] [boundary marker]\n"); + printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: <segment #> <endpoint> <endpoint> [boundary marker]\n"); + printf(" One line: <# of holes>\n"); + printf(" Following lines: <hole #> <x> <y>\n"); + printf( +" Optional line: <# of regional attributes and/or area constraints>\n"); + printf( +" Optional following lines: <constraint #> <x> <y> <attrib> <max area>\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: <triangle #> <maximum area>\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: <edge #> <endpoint> <endpoint> [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(" <edge #> <endpoint> -1 <direction x> <direction y>\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: <triangle #> <neighbor> <neighbor> <neighbor>\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 index 70cd6596..e7d87d01 100644 --- a/contrib/gtkgensurf/triangle.h +++ b/contrib/gtkgensurf/triangle.h @@ -1,288 +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 +/*****************************************************************************/ +/* */ +/* (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/hydratoolz/plugin.h b/contrib/hydratoolz/plugin.h index 493fa839..42b3c20c 100644 --- a/contrib/hydratoolz/plugin.h +++ b/contrib/hydratoolz/plugin.h @@ -1,51 +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 <gdk/gdkkeysyms.h> -//#include <gtk/gtk.h> -#include <stdio.h> -#include <stdlib.h> - -#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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <gdk/gdkkeysyms.h> +//#include <gtk/gtk.h> +#include <stdio.h> +#include <stdlib.h> + +#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/AboutDialog.h b/contrib/prtview/AboutDialog.h index 73dbad78..66d8c0d0 100644 --- a/contrib/prtview/AboutDialog.h +++ b/contrib/prtview/AboutDialog.h @@ -1,72 +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_) +/* +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.h b/contrib/prtview/ConfigDialog.h index 7ca84920..11690fdc 100644 --- a/contrib/prtview/ConfigDialog.h +++ b/contrib/prtview/ConfigDialog.h @@ -1,107 +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_) +/* +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.h b/contrib/prtview/LoadPortalFileDialog.h index c11c01ea..4540c104 100644 --- a/contrib/prtview/LoadPortalFileDialog.h +++ b/contrib/prtview/LoadPortalFileDialog.h @@ -1,77 +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_) +/* +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/gtkdlgs.h b/contrib/prtview/gtkdlgs.h index afa3ea74..37ca5031 100644 --- a/contrib/prtview/gtkdlgs.h +++ b/contrib/prtview/gtkdlgs.h @@ -1,27 +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_ +/* +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.h b/contrib/prtview/portals.h index 33bac1ec..13c7b89f 100644 --- a/contrib/prtview/portals.h +++ b/contrib/prtview/portals.h @@ -1,125 +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_ +/* +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.h b/contrib/prtview/prtview.h index e478f7d9..468df3fc 100644 --- a/contrib/prtview/prtview.h +++ b/contrib/prtview/prtview.h @@ -1,29 +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_) +/* +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/resource.h b/contrib/prtview/resource.h index afa9db6e..5fdce405 100644 --- a/contrib/prtview/resource.h +++ b/contrib/prtview/resource.h @@ -1,42 +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 +//{{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.h b/contrib/prtview/stdafx.h index b4afbc8e..e251fa79 100644 --- a/contrib/prtview/stdafx.h +++ b/contrib/prtview/stdafx.h @@ -1,79 +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 <gtk/gtk.h> - -#if defined(__linux__) || defined(__APPLE__) -#include <GL/glx.h> - -// 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 +/* +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 <gtk/gtk.h> + +#if defined(__linux__) || defined(__APPLE__) +#include <GL/glx.h> + +// 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/XMLPush/StdAfx.h b/docs/developer/XMLPush/StdAfx.h index fbb8d5e2..628f0aba 100644 --- a/docs/developer/XMLPush/StdAfx.h +++ b/docs/developer/XMLPush/StdAfx.h @@ -1,22 +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" +// 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/manual/quake3/Compile_Manual/cfgq3.c b/docs/manual/quake3/Compile_Manual/cfgq3.c index b3694bef..47e43c80 100644 --- a/docs/manual/quake3/Compile_Manual/cfgq3.c +++ b/docs/manual/quake3/Compile_Manual/cfgq3.c @@ -1,78 +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 -} +//=========================================================================== +// 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/include/aboutmsg.h b/include/aboutmsg.h index 213fe347..33748496 100644 --- a/include/aboutmsg.h +++ b/include/aboutmsg.h @@ -1,2 +1,2 @@ -// generated header, see makeversion.py -#define RADIANT_ABOUTMSG "ZeroRadiant build" +// generated header, see makeversion.py +#define RADIANT_ABOUTMSG "ZeroRadiant build" diff --git a/include/gtkr_list.h b/include/gtkr_list.h index 64ac1710..760f09f7 100644 --- a/include/gtkr_list.h +++ b/include/gtkr_list.h @@ -1,23 +1,23 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 <list> -#include "stl_check.h" +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <list> +#include "stl_check.h" diff --git a/include/gtkr_vector.h b/include/gtkr_vector.h index 3964be67..a070cf46 100644 --- a/include/gtkr_vector.h +++ b/include/gtkr_vector.h @@ -1,23 +1,23 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 <vector> -#include "stl_check.h" +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <vector> +#include "stl_check.h" diff --git a/include/ibrush.h b/include/ibrush.h index 47eb7a81..e191ac26 100644 --- a/include/ibrush.h +++ b/include/ibrush.h @@ -1,73 +1,73 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IBRUSH_H_ -#define _IBRUSH_H_ - -// -// API for brush stuff -// - -#define BRUSH_MAJOR "brush" -// {c1c3f567-2541-4aa3-9d5b-031fbe2a013b} -static const GUID QERBrushTable_GUID = -{ 0xc1c3f567, 0x2541, 0x4aa3, { 0x9d, 0x5b, 0x03, 0x1f, 0xbe, 0x2a, 0x01, 0x3b } }; - -typedef void (* PFN_BRUSHADDTOLIST) (brush_t *b, brush_t *lst); -typedef void (* PFN_BRUSHBUILD) (brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest); -typedef brush_t* (* PFN_BRUSHCREATE) (vec3_t mins, vec3_t maxs, texdef_t *texdef); -typedef void (* PFN_BRUSHFREE) (brush_t *b, bool bRemoveNode); -typedef void (* PFN_BRUSHROTATE) (brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild); -typedef brush_t* (* PFN_BRUSHALLOC) (); -typedef int (* PFN_BPMESSAGEBOX) (int); -typedef face_t* (* PFN_FACEALLOC) (void); -typedef eclass_t* (* PFN_HASMODEL) (brush_t *b); - -struct _QERBrushTable -{ - int m_nSize; - PFN_BRUSHADDTOLIST m_pfnBrush_AddToList; - PFN_BRUSHBUILD m_pfnBrush_Build; - PFN_BRUSHCREATE m_pfnBrush_Create; - PFN_BRUSHFREE m_pfnBrush_Free; - PFN_BRUSHROTATE m_pfnBrush_Rotate; - PFN_BRUSHALLOC m_pfnBrushAlloc; - PFN_BPMESSAGEBOX m_pfnBP_MessageBox; - PFN_FACEALLOC m_pfnFace_Alloc; - PFN_HASMODEL m_pfnHasModel; -}; - -#ifdef USE_BRUSHTABLE_DEFINE -#ifndef __BRUSHTABLENAME -#define __BRUSHTABLENAME g_BrushTable -#endif -#define Brush_AddToList __BRUSHTABLENAME.m_pfnBrush_AddToList -#define Brush_Build __BRUSHTABLENAME.m_pfnBrush_Build -#define Brush_Create __BRUSHTABLENAME.m_pfnBrush_Create -#define Brush_Free __BRUSHTABLENAME.m_pfnBrush_Free -#define Brush_Rotate __BRUSHTABLENAME.m_pfnBrush_Rotate -#define Brush_Alloc __BRUSHTABLENAME.m_pfnBrushAlloc -#define BP_MessageBox __BRUSHTABLENAME.m_pfnBP_MessageBox -#define Face_Alloc __BRUSHTABLENAME.m_pfnFace_Alloc -#define HasModel __BRUSHTABLENAME.m_pfnHasModel -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IBRUSH_H_ +#define _IBRUSH_H_ + +// +// API for brush stuff +// + +#define BRUSH_MAJOR "brush" +// {c1c3f567-2541-4aa3-9d5b-031fbe2a013b} +static const GUID QERBrushTable_GUID = +{ 0xc1c3f567, 0x2541, 0x4aa3, { 0x9d, 0x5b, 0x03, 0x1f, 0xbe, 0x2a, 0x01, 0x3b } }; + +typedef void (* PFN_BRUSHADDTOLIST) (brush_t *b, brush_t *lst); +typedef void (* PFN_BRUSHBUILD) (brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest); +typedef brush_t* (* PFN_BRUSHCREATE) (vec3_t mins, vec3_t maxs, texdef_t *texdef); +typedef void (* PFN_BRUSHFREE) (brush_t *b, bool bRemoveNode); +typedef void (* PFN_BRUSHROTATE) (brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild); +typedef brush_t* (* PFN_BRUSHALLOC) (); +typedef int (* PFN_BPMESSAGEBOX) (int); +typedef face_t* (* PFN_FACEALLOC) (void); +typedef eclass_t* (* PFN_HASMODEL) (brush_t *b); + +struct _QERBrushTable +{ + int m_nSize; + PFN_BRUSHADDTOLIST m_pfnBrush_AddToList; + PFN_BRUSHBUILD m_pfnBrush_Build; + PFN_BRUSHCREATE m_pfnBrush_Create; + PFN_BRUSHFREE m_pfnBrush_Free; + PFN_BRUSHROTATE m_pfnBrush_Rotate; + PFN_BRUSHALLOC m_pfnBrushAlloc; + PFN_BPMESSAGEBOX m_pfnBP_MessageBox; + PFN_FACEALLOC m_pfnFace_Alloc; + PFN_HASMODEL m_pfnHasModel; +}; + +#ifdef USE_BRUSHTABLE_DEFINE +#ifndef __BRUSHTABLENAME +#define __BRUSHTABLENAME g_BrushTable +#endif +#define Brush_AddToList __BRUSHTABLENAME.m_pfnBrush_AddToList +#define Brush_Build __BRUSHTABLENAME.m_pfnBrush_Build +#define Brush_Create __BRUSHTABLENAME.m_pfnBrush_Create +#define Brush_Free __BRUSHTABLENAME.m_pfnBrush_Free +#define Brush_Rotate __BRUSHTABLENAME.m_pfnBrush_Rotate +#define Brush_Alloc __BRUSHTABLENAME.m_pfnBrushAlloc +#define BP_MessageBox __BRUSHTABLENAME.m_pfnBP_MessageBox +#define Face_Alloc __BRUSHTABLENAME.m_pfnFace_Alloc +#define HasModel __BRUSHTABLENAME.m_pfnHasModel +#endif + +#endif diff --git a/include/ibspfrontend.h b/include/ibspfrontend.h index c00217fb..973f0633 100644 --- a/include/ibspfrontend.h +++ b/include/ibspfrontend.h @@ -1,77 +1,77 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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: -// interface for BSP frontends plugins -// - -// DONE: - change BSP menu to Q3Build menu ? -// DONE: - detect when Q3Build dies ? -// DELAYED: - hotkeys ! -// SUCCESS: - try again getting feedback from Q3Build - -#ifndef __IBSPFRONTEND_H_ -#define __IBSPFRONTEND_H_ - -// define a GUID for this interface so plugins can access and reference it -// {8ED6A480-BA5E-11d3-A3E3-0004AC96D4C3} -static const GUID QERPlugBSPFrontendTable_GUID = -{ 0x8ed6a480, 0xba5e, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -// ask the plugin about the items to show up in the BSP menu -typedef char * (WINAPI* PFN_GETBSPMENU) (); -// dispatch a BSP menu command -typedef void (WINAPI* PFN_DISPATCHBSPCOMMAND) (char *); -// this one gets called after a monitoring loop ends -// 0: all good -// 1: timed out / Radiant didn't get the connection -// 2: got a connection, compilation ended with an error -typedef void (WINAPI* PFN_ENDLISTEN) (int status); - -struct _QERPlugBSPFrontendTable -{ - int m_nSize; - PFN_GETBSPMENU m_pfnGetBSPMenu; - PFN_DISPATCHBSPCOMMAND m_pfnDispatchBSPCommand; - PFN_ENDLISTEN m_pfnEndListen; -}; - -// interface provided by Radiant to the plugin -// {A2CCF366-BA60-11d3-A3E3-0004AC96D4C3} -static const GUID QERAppBSPFrontendTable_GUID = -{ 0xa2ccf366, 0xba60, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -typedef char * (WINAPI* PFN_GETMAPNAME) (); -typedef void (WINAPI* PFN_LISTEN) (); -typedef void (WINAPI* PFN_SLEEP) (); - -struct _QERAppBSPFrontendTable -{ - int m_nSize; - PFN_GETMAPNAME m_pfnGetMapName; - PFN_LISTEN m_pfnListen; - PFN_SLEEP m_pfnSleep; - //++timo TODO: needs a hook to reset the debug window (in regular mode it's done at startup of the BSP operation) -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// interface for BSP frontends plugins +// + +// DONE: - change BSP menu to Q3Build menu ? +// DONE: - detect when Q3Build dies ? +// DELAYED: - hotkeys ! +// SUCCESS: - try again getting feedback from Q3Build + +#ifndef __IBSPFRONTEND_H_ +#define __IBSPFRONTEND_H_ + +// define a GUID for this interface so plugins can access and reference it +// {8ED6A480-BA5E-11d3-A3E3-0004AC96D4C3} +static const GUID QERPlugBSPFrontendTable_GUID = +{ 0x8ed6a480, 0xba5e, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// ask the plugin about the items to show up in the BSP menu +typedef char * (WINAPI* PFN_GETBSPMENU) (); +// dispatch a BSP menu command +typedef void (WINAPI* PFN_DISPATCHBSPCOMMAND) (char *); +// this one gets called after a monitoring loop ends +// 0: all good +// 1: timed out / Radiant didn't get the connection +// 2: got a connection, compilation ended with an error +typedef void (WINAPI* PFN_ENDLISTEN) (int status); + +struct _QERPlugBSPFrontendTable +{ + int m_nSize; + PFN_GETBSPMENU m_pfnGetBSPMenu; + PFN_DISPATCHBSPCOMMAND m_pfnDispatchBSPCommand; + PFN_ENDLISTEN m_pfnEndListen; +}; + +// interface provided by Radiant to the plugin +// {A2CCF366-BA60-11d3-A3E3-0004AC96D4C3} +static const GUID QERAppBSPFrontendTable_GUID = +{ 0xa2ccf366, 0xba60, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +typedef char * (WINAPI* PFN_GETMAPNAME) (); +typedef void (WINAPI* PFN_LISTEN) (); +typedef void (WINAPI* PFN_SLEEP) (); + +struct _QERAppBSPFrontendTable +{ + int m_nSize; + PFN_GETMAPNAME m_pfnGetMapName; + PFN_LISTEN m_pfnListen; + PFN_SLEEP m_pfnSleep; + //++timo TODO: needs a hook to reset the debug window (in regular mode it's done at startup of the BSP operation) +}; + +#endif diff --git a/include/icamera.h b/include/icamera.h index 22faf0fe..07425ec4 100644 --- a/include/icamera.h +++ b/include/icamera.h @@ -1,45 +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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// camera interface -// - -#ifndef __ICAMERA_H_ -#define __ICAMERA_H_ - -#define CAMERA_MAJOR "camera" - -typedef void (* PFN_GETCAMERA) ( vec3_t origin, vec3_t angles ); -typedef void (* PFN_SETCAMERA) ( vec3_t origin, vec3_t angles ); -typedef void (* PFN_GETCAMWINDOWEXTENTS) ( int *x, int *y, int *width, int *height ); - -struct _QERCameraTable -{ - int m_nSize; - PFN_GETCAMERA m_pfnGetCamera; - PFN_SETCAMERA m_pfnSetCamera; - PFN_GETCAMWINDOWEXTENTS m_pfnGetCamWindowExtents; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// camera interface +// + +#ifndef __ICAMERA_H_ +#define __ICAMERA_H_ + +#define CAMERA_MAJOR "camera" + +typedef void (* PFN_GETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_SETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_GETCAMWINDOWEXTENTS) ( int *x, int *y, int *width, int *height ); + +struct _QERCameraTable +{ + int m_nSize; + PFN_GETCAMERA m_pfnGetCamera; + PFN_SETCAMERA m_pfnSetCamera; + PFN_GETCAMWINDOWEXTENTS m_pfnGetCamWindowExtents; +}; + +#endif diff --git a/include/idata.h b/include/idata.h index eb39cfa9..fe453366 100644 --- a/include/idata.h +++ b/include/idata.h @@ -1,57 +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: -// interface table to access low-level data inside Radiant (brushes, patches and generic editing primitives) - -#ifndef __IDATA_H_ -#define __IDATA_H_ - -// FIXME TTimo this should probably go away and be replaced by a more flat structure -// having to write access functions for every single var is a big annoyance -// see IMapData_t, generalize it? - -#define DATA_MAJOR "data" -// FIXME: remove -// define a GUID for this interface so plugins can access and reference it -// {608A9870-BCE7-11d4-A454-0004AC96D4C3} -static const GUID QERAppDataTable_GUID = -{ 0x608a9870, 0xbce7, 0x11d4, { 0xa4, 0x54, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - - -// pointers to active_brushes, selected_brushes and filtered_brushes -typedef brush_t* (WINAPI* PFN_ACTIVEBRUSHES) (); -typedef brush_t* (WINAPI* PFN_SELECTEDBRUSHES) (); -typedef brush_t* (WINAPI* PFN_FILTEREDBRUSHES) (); -typedef CPtrArray* (WINAPI* PFN_LSTSKINCACHE) (); - -struct _QERAppDataTable -{ - int m_nSize; - PFN_ACTIVEBRUSHES m_pfnActiveBrushes; - PFN_SELECTEDBRUSHES m_pfnSelectedBrushes; - PFN_FILTEREDBRUSHES m_pfnFilteredBrushes; - PFN_LSTSKINCACHE m_pfnLstSkinCache; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// interface table to access low-level data inside Radiant (brushes, patches and generic editing primitives) + +#ifndef __IDATA_H_ +#define __IDATA_H_ + +// FIXME TTimo this should probably go away and be replaced by a more flat structure +// having to write access functions for every single var is a big annoyance +// see IMapData_t, generalize it? + +#define DATA_MAJOR "data" +// FIXME: remove +// define a GUID for this interface so plugins can access and reference it +// {608A9870-BCE7-11d4-A454-0004AC96D4C3} +static const GUID QERAppDataTable_GUID = +{ 0x608a9870, 0xbce7, 0x11d4, { 0xa4, 0x54, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + + +// pointers to active_brushes, selected_brushes and filtered_brushes +typedef brush_t* (WINAPI* PFN_ACTIVEBRUSHES) (); +typedef brush_t* (WINAPI* PFN_SELECTEDBRUSHES) (); +typedef brush_t* (WINAPI* PFN_FILTEREDBRUSHES) (); +typedef CPtrArray* (WINAPI* PFN_LSTSKINCACHE) (); + +struct _QERAppDataTable +{ + int m_nSize; + PFN_ACTIVEBRUSHES m_pfnActiveBrushes; + PFN_SELECTEDBRUSHES m_pfnSelectedBrushes; + PFN_FILTEREDBRUSHES m_pfnFilteredBrushes; + PFN_LSTSKINCACHE m_pfnLstSkinCache; +}; + +#endif diff --git a/include/idatastream.h b/include/idatastream.h index 8f6b0b8c..19534aa4 100644 --- a/include/idatastream.h +++ b/include/idatastream.h @@ -1,71 +1,71 @@ -/* -Copyright (c) 2001, Loki software, inc. -modifications (c) 2001, Id 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 _ISTREAM_H_ -#define _ISTREAM_H_ - -/*! -API for data streams - -Based on an initial implementation by Loki software -modified to be abstracted and shared across modules - -NOTE: why IDataStream and not IStream? because IStream is defined in windows IDL headers -*/ - -class IDataStream -{ -public: - IDataStream(); - virtual ~IDataStream(); - - virtual void IncRef () = 0; ///< Increment the number of references to this object - virtual void DecRef () = 0; ///< Decrement the reference count - - virtual unsigned long GetPosition() const = 0; - virtual unsigned long Seek(long lOff, int nFrom) = 0; - virtual void SetLength(unsigned long nNewLen) = 0; - virtual unsigned long GetLength() const = 0; - - virtual char* ReadString(char* pBuf, unsigned long nMax)=0; - virtual unsigned long Read(void* pBuf, unsigned long nCount)=0; - virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0; - virtual int GetChar()=0; - virtual int PutChar(int c)=0; - - virtual void printf(const char*, ...) = 0; ///< completely matches the usual printf behaviour - - virtual void Abort()=0; - virtual void Flush()=0; - virtual void Close()=0; -}; - -#endif // _ISTREAM_H_ +/* +Copyright (c) 2001, Loki software, inc. +modifications (c) 2001, Id 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 _ISTREAM_H_ +#define _ISTREAM_H_ + +/*! +API for data streams + +Based on an initial implementation by Loki software +modified to be abstracted and shared across modules + +NOTE: why IDataStream and not IStream? because IStream is defined in windows IDL headers +*/ + +class IDataStream +{ +public: + IDataStream(); + virtual ~IDataStream(); + + virtual void IncRef () = 0; ///< Increment the number of references to this object + virtual void DecRef () = 0; ///< Decrement the reference count + + virtual unsigned long GetPosition() const = 0; + virtual unsigned long Seek(long lOff, int nFrom) = 0; + virtual void SetLength(unsigned long nNewLen) = 0; + virtual unsigned long GetLength() const = 0; + + virtual char* ReadString(char* pBuf, unsigned long nMax)=0; + virtual unsigned long Read(void* pBuf, unsigned long nCount)=0; + virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0; + virtual int GetChar()=0; + virtual int PutChar(int c)=0; + + virtual void printf(const char*, ...) = 0; ///< completely matches the usual printf behaviour + + virtual void Abort()=0; + virtual void Flush()=0; + virtual void Close()=0; +}; + +#endif // _ISTREAM_H_ diff --git a/include/ieclass.h b/include/ieclass.h index bfca1d60..cb32647c 100644 --- a/include/ieclass.h +++ b/include/ieclass.h @@ -1,84 +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 -*/ - -/*! \file ieclass.h - \brief entity files loader API - this describes the APIs involved when loading entity description files - (initially, .def and .fgd) -*/ - -#ifndef _IECLASS_H_ -#define _IECLASS_H_ - -#define ECLASS_MAJOR "eclass" - -typedef void (* PFN_ECLASS_SCANFILE) (char *filename); -typedef const char* (* PFN_ECLASS_GETEXTENSION) (); - -struct _EClassTable -{ - int m_nSize; - PFN_ECLASS_SCANFILE m_pfnScanFile; - PFN_ECLASS_GETEXTENSION m_pfnGetExtension; -}; - -#ifdef USE_ECLASSTABLE_DEFINE -#ifndef __ECLASSTABLENAME -#define __ECLASSTABLENAME g_EClassTable -#endif -#define EClass_ScanFile __ECLASSTABLENAME.m_pfnEClass_ScanFile -#define EClass_GetExtension __ECLASSTABLENAME.m_pfnEClass_GetExtension -#endif - -#define ECLASSMANAGER_MAJOR "eclassmanager" - -typedef void (* PFN_ECLASS_INSERTALPHABETIZED) (eclass_t *e); -typedef eclass_t** (* PFN_GET_ECLASS_E) (); -typedef void (* PFN_SET_ECLASS_FOUND) (qboolean); -typedef qboolean (* PFN_GET_PARSING_SINGLE) (); -typedef eclass_t* (* PFN_ECLASS_CREATE) (const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments); -typedef eclass_t* (* PFN_ECLASS_FORNAME) (const char* name, qboolean has_brushes); - -struct _EClassManagerTable -{ - int m_nSize; - PFN_ECLASS_INSERTALPHABETIZED m_pfnEclass_InsertAlphabetized; - PFN_GET_ECLASS_E m_pfnGet_Eclass_E; - PFN_SET_ECLASS_FOUND m_pfnSet_Eclass_Found; - PFN_GET_PARSING_SINGLE m_pfnGet_Parsing_Single; - PFN_ECLASS_CREATE m_pfnEClass_Create; - PFN_ECLASS_FORNAME m_pfnEclass_ForName; -}; - -#ifdef USE_ECLASSMANAGER_DEFINE -#ifndef __ECLASSMANAGERTABLENAME -#define __ECLASSMANAGERTABLENAME g_EClassManagerTable -#endif -#define Eclass_InsertAlphabetized __ECLASSMANAGERTABLENAME.m_pfnEclass_InsertAlphabetized -#define Get_Eclass_E __ECLASSMANAGERTABLENAME.m_pfnGet_Eclass_E -#define Set_Eclass_Found __ECLASSMANAGERTABLENAME.m_pfnSet_Eclass_Found -#define Get_Parsing_Single __ECLASSMANAGERTABLENAME.m_pfnGet_Parsing_Single -#define EClass_Create __ECLASSMANAGERTABLENAME.m_pfnEClass_Create -#define Eclass_ForName __ECLASSMANAGERTABLENAME.m_pfnEclass_ForName -#endif - -#endif - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! \file ieclass.h + \brief entity files loader API + this describes the APIs involved when loading entity description files + (initially, .def and .fgd) +*/ + +#ifndef _IECLASS_H_ +#define _IECLASS_H_ + +#define ECLASS_MAJOR "eclass" + +typedef void (* PFN_ECLASS_SCANFILE) (char *filename); +typedef const char* (* PFN_ECLASS_GETEXTENSION) (); + +struct _EClassTable +{ + int m_nSize; + PFN_ECLASS_SCANFILE m_pfnScanFile; + PFN_ECLASS_GETEXTENSION m_pfnGetExtension; +}; + +#ifdef USE_ECLASSTABLE_DEFINE +#ifndef __ECLASSTABLENAME +#define __ECLASSTABLENAME g_EClassTable +#endif +#define EClass_ScanFile __ECLASSTABLENAME.m_pfnEClass_ScanFile +#define EClass_GetExtension __ECLASSTABLENAME.m_pfnEClass_GetExtension +#endif + +#define ECLASSMANAGER_MAJOR "eclassmanager" + +typedef void (* PFN_ECLASS_INSERTALPHABETIZED) (eclass_t *e); +typedef eclass_t** (* PFN_GET_ECLASS_E) (); +typedef void (* PFN_SET_ECLASS_FOUND) (qboolean); +typedef qboolean (* PFN_GET_PARSING_SINGLE) (); +typedef eclass_t* (* PFN_ECLASS_CREATE) (const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments); +typedef eclass_t* (* PFN_ECLASS_FORNAME) (const char* name, qboolean has_brushes); + +struct _EClassManagerTable +{ + int m_nSize; + PFN_ECLASS_INSERTALPHABETIZED m_pfnEclass_InsertAlphabetized; + PFN_GET_ECLASS_E m_pfnGet_Eclass_E; + PFN_SET_ECLASS_FOUND m_pfnSet_Eclass_Found; + PFN_GET_PARSING_SINGLE m_pfnGet_Parsing_Single; + PFN_ECLASS_CREATE m_pfnEClass_Create; + PFN_ECLASS_FORNAME m_pfnEclass_ForName; +}; + +#ifdef USE_ECLASSMANAGER_DEFINE +#ifndef __ECLASSMANAGERTABLENAME +#define __ECLASSMANAGERTABLENAME g_EClassManagerTable +#endif +#define Eclass_InsertAlphabetized __ECLASSMANAGERTABLENAME.m_pfnEclass_InsertAlphabetized +#define Get_Eclass_E __ECLASSMANAGERTABLENAME.m_pfnGet_Eclass_E +#define Set_Eclass_Found __ECLASSMANAGERTABLENAME.m_pfnSet_Eclass_Found +#define Get_Parsing_Single __ECLASSMANAGERTABLENAME.m_pfnGet_Parsing_Single +#define EClass_Create __ECLASSMANAGERTABLENAME.m_pfnEClass_Create +#define Eclass_ForName __ECLASSMANAGERTABLENAME.m_pfnEclass_ForName +#endif + +#endif + diff --git a/include/ientity.h b/include/ientity.h index 51ca389f..015cf1ec 100644 --- a/include/ientity.h +++ b/include/ientity.h @@ -1,116 +1,116 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IENTITY_H_ -#define _IENTITY_H_ - -// -// API for entity manip stuff -// - -// FIXME TTimo this prolly needs to merge with iepairs.h? - -/*! -SPoG -generic "entity" module... -at first, there will only be one implementation for all entities, -perhaps later there will be one for each entity type? -it would probably make more sense to have a single implementation, -a generic one that is very flexible and can adapt the visualisation of -itself depending on an xml config specified in the entity definitions file -*/ -#define ENTITY_MAJOR "entity" -// {A1C9F9FD-75D5-4e4d-9D65-235D6D3F254C} -static const GUID QEREntityTable_GUID = -{ 0xa1c9f9fd, 0x75d5, 0x4e4d, { 0x9d, 0x65, 0x23, 0x5d, 0x6d, 0x3f, 0x25, 0x4c } }; - -typedef entity_t* (* PFN_ENTITYALLOC) (); -typedef void (* PFN_ENTITYFREE) (entity_t *e); -typedef entity_t* (* PFN_ENTITYCREATE) (eclass_t *c); -typedef entity_t* (* PFN_ENTITYCLONE) (entity_t *e); -typedef void (* PFN_ENTITYSETKEYVALUE) (entity_t *ent, const char *key, const char *value); -typedef void (* PFN_ENTITYDELETEKEY) (entity_t *ent, const char *key); -typedef const char* (* PFN_ENTITYVALUEFORKEY) (entity_t *ent, const char *key); -typedef float (* PFN_ENTITYFLOATFORKEY) (entity_t *ent, const char *key); -typedef int (* PFN_ENTITYINTFORKEY) (entity_t *ent, const char *key); -typedef void (* PFN_ENTITYVECTORFORKEY) (entity_t *ent, const char *key, vec3_t vec); -typedef void (* PFN_ENTITYADDTOLIST) (entity_t *e, entity_t *lst); -typedef void (* PFN_ENTITYREMOVEFROMLIST) (entity_t *e); -typedef void (* PFN_ENTITYLINKBRUSH) (entity_t *e, brush_t *b); -typedef void (* PFN_ENTITYUNLINKBRUSH) (brush_t *b); -typedef void (* PFN_ENTITYDRAWLIGHT) (entity_t* e, int nGLState, int pref, int nViewType); -typedef int (* PFN_ENTITYMEMORYSIZE) (entity_t *e); -typedef void (* PFN_ENTITYUPDATEMODEL) (entity_t *e); -typedef epair_t* (* PFN_ALLOCATEEPAIR) (const char *key, const char *value); -typedef epair_t** (* PFN_GETENTITYKEYVALLIST) (entity_t *e); -typedef void (* PFN_SETENTITYKEYVALLIST) (entity_t *e, epair_t* ep); - - -struct _QEREntityTable -{ - int m_nSize; - PFN_ENTITYALLOC m_pfnEntity_Alloc; - PFN_ENTITYFREE m_pfnEntity_Free; - PFN_ENTITYCREATE m_pfnEntity_Create; - PFN_ENTITYCLONE m_pfnEntity_Clone; - PFN_ENTITYSETKEYVALUE m_pfnSetKeyValue; - PFN_ENTITYDELETEKEY m_pfnDeleteKey; - PFN_ENTITYVALUEFORKEY m_pfnValueForKey; - PFN_ENTITYFLOATFORKEY m_pfnFloatForKey; - PFN_ENTITYINTFORKEY m_pfnIntForKey; - PFN_ENTITYVECTORFORKEY m_pfnGetVectorForKey; - PFN_ENTITYADDTOLIST m_pfnEntity_AddToList; - PFN_ENTITYREMOVEFROMLIST m_pfnEntity_RemoveFromList; - PFN_ENTITYLINKBRUSH m_pfnEntity_LinkBrush; - PFN_ENTITYUNLINKBRUSH m_pfnEntity_UnlinkBrush; - PFN_ENTITYDRAWLIGHT m_pfnDrawLight; - PFN_ENTITYMEMORYSIZE m_pfnEntity_MemorySize; - PFN_ALLOCATEEPAIR m_pfnAllocateEpair; - PFN_GETENTITYKEYVALLIST m_pfnGetEntityKeyValList; - PFN_SETENTITYKEYVALLIST m_pfnSetEntityKeyValList; -}; - -#ifdef USE_ENTITYTABLE_DEFINE -#ifndef __ENTITYTABLENAME -#define __ENTITYTABLENAME g_EntityTable -#endif -#define Entity_Alloc __ENTITYTABLENAME.m_pfnEntity_Alloc -#define Entity_Free __ENTITYTABLENAME.m_pfnEntity_Free -#define Entity_Clone __ENTITYTABLENAME.m_pfnEntity_Clone -#define SetKeyValue __ENTITYTABLENAME.m_pfnSetKeyValue -#define DeleteKey __ENTITYTABLENAME.m_pfnDeleteKey -#define ValueForKey __ENTITYTABLENAME.m_pfnValueForKey -#define FloatForKey __ENTITYTABLENAME.m_pfnFloatForKey -#define IntForKey __ENTITYTABLENAME.m_pfnIntForKey -#define GetVectorForKey __ENTITYTABLENAME.m_pfnGetVectorForKey -#define Entity_AddToList __ENTITYTABLENAME.m_pfnEntity_AddToList -#define Entity_RemoveFromList __ENTITYTABLENAME.m_pfnEntity_RemoveFromList -#define Entity_LinkBrush __ENTITYTABLENAME.m_pfnEntity_LinkBrush -#define Entity_UnlinkBrush __ENTITYTABLENAME.m_pfnEntity_UnlinkBrush -#define DrawLight __ENTITYTABLENAME.m_pfnDrawLight -#define Entity_MemorySize __ENTITYTABLENAME.m_pfnEntity_MemorySize -#define Entity_AllocateEpair __ENTITYTABLENAME.m_pfnAllocateEpair -#define Entity_GetKeyValList __ENTITYTABLENAME.m_pfnGetEntityKeyValList -#define Entity_SetKeyValList __ENTITYTABLENAME.m_pfnSetEntityKeyValList -#endif - -#endif - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IENTITY_H_ +#define _IENTITY_H_ + +// +// API for entity manip stuff +// + +// FIXME TTimo this prolly needs to merge with iepairs.h? + +/*! +SPoG +generic "entity" module... +at first, there will only be one implementation for all entities, +perhaps later there will be one for each entity type? +it would probably make more sense to have a single implementation, +a generic one that is very flexible and can adapt the visualisation of +itself depending on an xml config specified in the entity definitions file +*/ +#define ENTITY_MAJOR "entity" +// {A1C9F9FD-75D5-4e4d-9D65-235D6D3F254C} +static const GUID QEREntityTable_GUID = +{ 0xa1c9f9fd, 0x75d5, 0x4e4d, { 0x9d, 0x65, 0x23, 0x5d, 0x6d, 0x3f, 0x25, 0x4c } }; + +typedef entity_t* (* PFN_ENTITYALLOC) (); +typedef void (* PFN_ENTITYFREE) (entity_t *e); +typedef entity_t* (* PFN_ENTITYCREATE) (eclass_t *c); +typedef entity_t* (* PFN_ENTITYCLONE) (entity_t *e); +typedef void (* PFN_ENTITYSETKEYVALUE) (entity_t *ent, const char *key, const char *value); +typedef void (* PFN_ENTITYDELETEKEY) (entity_t *ent, const char *key); +typedef const char* (* PFN_ENTITYVALUEFORKEY) (entity_t *ent, const char *key); +typedef float (* PFN_ENTITYFLOATFORKEY) (entity_t *ent, const char *key); +typedef int (* PFN_ENTITYINTFORKEY) (entity_t *ent, const char *key); +typedef void (* PFN_ENTITYVECTORFORKEY) (entity_t *ent, const char *key, vec3_t vec); +typedef void (* PFN_ENTITYADDTOLIST) (entity_t *e, entity_t *lst); +typedef void (* PFN_ENTITYREMOVEFROMLIST) (entity_t *e); +typedef void (* PFN_ENTITYLINKBRUSH) (entity_t *e, brush_t *b); +typedef void (* PFN_ENTITYUNLINKBRUSH) (brush_t *b); +typedef void (* PFN_ENTITYDRAWLIGHT) (entity_t* e, int nGLState, int pref, int nViewType); +typedef int (* PFN_ENTITYMEMORYSIZE) (entity_t *e); +typedef void (* PFN_ENTITYUPDATEMODEL) (entity_t *e); +typedef epair_t* (* PFN_ALLOCATEEPAIR) (const char *key, const char *value); +typedef epair_t** (* PFN_GETENTITYKEYVALLIST) (entity_t *e); +typedef void (* PFN_SETENTITYKEYVALLIST) (entity_t *e, epair_t* ep); + + +struct _QEREntityTable +{ + int m_nSize; + PFN_ENTITYALLOC m_pfnEntity_Alloc; + PFN_ENTITYFREE m_pfnEntity_Free; + PFN_ENTITYCREATE m_pfnEntity_Create; + PFN_ENTITYCLONE m_pfnEntity_Clone; + PFN_ENTITYSETKEYVALUE m_pfnSetKeyValue; + PFN_ENTITYDELETEKEY m_pfnDeleteKey; + PFN_ENTITYVALUEFORKEY m_pfnValueForKey; + PFN_ENTITYFLOATFORKEY m_pfnFloatForKey; + PFN_ENTITYINTFORKEY m_pfnIntForKey; + PFN_ENTITYVECTORFORKEY m_pfnGetVectorForKey; + PFN_ENTITYADDTOLIST m_pfnEntity_AddToList; + PFN_ENTITYREMOVEFROMLIST m_pfnEntity_RemoveFromList; + PFN_ENTITYLINKBRUSH m_pfnEntity_LinkBrush; + PFN_ENTITYUNLINKBRUSH m_pfnEntity_UnlinkBrush; + PFN_ENTITYDRAWLIGHT m_pfnDrawLight; + PFN_ENTITYMEMORYSIZE m_pfnEntity_MemorySize; + PFN_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_GETENTITYKEYVALLIST m_pfnGetEntityKeyValList; + PFN_SETENTITYKEYVALLIST m_pfnSetEntityKeyValList; +}; + +#ifdef USE_ENTITYTABLE_DEFINE +#ifndef __ENTITYTABLENAME +#define __ENTITYTABLENAME g_EntityTable +#endif +#define Entity_Alloc __ENTITYTABLENAME.m_pfnEntity_Alloc +#define Entity_Free __ENTITYTABLENAME.m_pfnEntity_Free +#define Entity_Clone __ENTITYTABLENAME.m_pfnEntity_Clone +#define SetKeyValue __ENTITYTABLENAME.m_pfnSetKeyValue +#define DeleteKey __ENTITYTABLENAME.m_pfnDeleteKey +#define ValueForKey __ENTITYTABLENAME.m_pfnValueForKey +#define FloatForKey __ENTITYTABLENAME.m_pfnFloatForKey +#define IntForKey __ENTITYTABLENAME.m_pfnIntForKey +#define GetVectorForKey __ENTITYTABLENAME.m_pfnGetVectorForKey +#define Entity_AddToList __ENTITYTABLENAME.m_pfnEntity_AddToList +#define Entity_RemoveFromList __ENTITYTABLENAME.m_pfnEntity_RemoveFromList +#define Entity_LinkBrush __ENTITYTABLENAME.m_pfnEntity_LinkBrush +#define Entity_UnlinkBrush __ENTITYTABLENAME.m_pfnEntity_UnlinkBrush +#define DrawLight __ENTITYTABLENAME.m_pfnDrawLight +#define Entity_MemorySize __ENTITYTABLENAME.m_pfnEntity_MemorySize +#define Entity_AllocateEpair __ENTITYTABLENAME.m_pfnAllocateEpair +#define Entity_GetKeyValList __ENTITYTABLENAME.m_pfnGetEntityKeyValList +#define Entity_SetKeyValList __ENTITYTABLENAME.m_pfnSetEntityKeyValList +#endif + +#endif + diff --git a/include/ifilesystem.h b/include/ifilesystem.h index 8a9a2006..e9c3e725 100644 --- a/include/ifilesystem.h +++ b/include/ifilesystem.h @@ -1,140 +1,140 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IFILESYSTEM_H_ -#define _IFILESYSTEM_H_ - -// -// Plugin interface for the virtual filesystem used by Radiant -// - -// NOTE: If you want to write a VFS plugin then you must export -// "QERPlug_ListInterfaces" and "QERPlug_RequestInterface" -// (see qerplugin.h for more information) - -#ifdef _WIN32 -#define VFS_NATIVESEPARATOR '\\' -#else -#define VFS_NATIVESEPARATOR '/' -#endif - -#define VFS_MAJOR "VFS" - -// return the file system supported by the plugin, for example: "quake1" or "quake3" -//typedef const char* (WINAPI* PFN_VFSGETFORMAT) (); -// add all files from a directory to the vfs -typedef void (* PFN_VFSINITDIRECTORY) (const char *path); -// free all resources used by the plugin -typedef void (* PFN_VFSSHUTDOWN) (); -// free memory allocated by VFS for this pointer -typedef void (* PFN_VFSFREEFILE) (void *p); -// return a GSList with all the directories under basedir -typedef GSList* (* PFN_VFSGETDIRLIST) (const char *basedir); -// return a GSList with all the files under basedir (extension can be NULL) -typedef GSList* (* PFN_VFSGETFILELIST) (const char *basedir, const char *extension); -// free a dirlist or filelist returned from one of the above functions -typedef void (* PFN_VFSCLEARFILEDIRLIST) (GSList **lst); -#define VFS_SEARCH_PAK 0x1 -#define VFS_SEARCH_DIR 0x2 -/*! -\brief return the number of files with the exact name described in filename -there can be several hits for a given file, or this can be used to check for existence -\param flags is optional and can be used with VFS_SEARCH_* bits, if flag is 0, everything is searched, else only the specified bits -paks are searched first, then search directories -*/ -typedef int (* PFN_VFSGETFILECOUNT) (const char *filename, int flags); -/*! -\brief load file, allocate buffer -\return -1 if fails or the size of the buffer allocated -\param index is used to load the i-th file in the search directories (see vfsGetFileCount) -this will scan in the search directories first, then it will search in the pak files -WARNING: the allocated buffer must be freed with a g_free call -NOTE TTimo: the g_free release is utter horror - see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 -*/ -typedef int (* PFN_VFSLOADFILE) (const char *filename, void **buffer, int index); -// load a file from it's full path into the buffer, returns the file size or -1 -// the allocated buffer must be freed with a g_free call -typedef int (* PFN_VFSLOADFULLPATHFILE) (const char *filename, void **buffer); -// takes an absolute file path, returns a shortened relative file path if the absolute path matches a valid basedir or NULL if an error occured -typedef char* (* PFN_VFSEXTRACTRELATIVEPATH) (const char *in); -/*! -\return the full path (in a static buff) to a file given it's relative path (NULL if not found) -\param index if several files are matching (as returned in a call to vfsGetFileCount), get the index-th file -\param flag 0 or a combination of VFS_SEARCH_PAK or VFS_SEARCH_DIR -HYDRA: - this now searches VFS/PAK files in addition to the filesystem - if FLAG is 0 then ONLY dirs are searched. - PAK's are searched before DIRs to mimic engine behaviour - index is ignored when searching PAK files. - when searching VFS, files are searched case insensitive. - -WARNING: if you use index from vfsGetFileCount, it works only with a vfsGetFileCount for the search directories only (not the pak files) -FIXME TTimo our VFS names are case insensitive. - this function is not able to build the full path from case-insensitive name - ( this is http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ) -*/ -typedef char* (* PFN_VFSGETFULLPATH) (const char *in, int index, int flag); -/*! -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. -FIXME: I'm not sure this is used / relevant anymore -*/ -typedef const char* (* PFN_VFSBASEPROMPTPATH) (); - -// VFS API -struct _QERFileSystemTable -{ - int m_nSize; - PFN_VFSINITDIRECTORY m_pfnInitDirectory; - PFN_VFSSHUTDOWN m_pfnShutdown; - PFN_VFSFREEFILE m_pfnFreeFile; - PFN_VFSGETDIRLIST m_pfnGetDirList; - PFN_VFSGETFILELIST m_pfnGetFileList; - PFN_VFSCLEARFILEDIRLIST m_pfnClearFileDirList; - PFN_VFSGETFILECOUNT m_pfnGetFileCount; - PFN_VFSLOADFILE m_pfnLoadFile; - PFN_VFSLOADFULLPATHFILE m_pfnLoadFullPathFile; - PFN_VFSEXTRACTRELATIVEPATH m_pfnExtractRelativePath; - PFN_VFSGETFULLPATH m_pfnGetFullPath; - PFN_VFSBASEPROMPTPATH m_pfnBasePromptPath; -}; - -#ifdef USE_VFSTABLE_DEFINE -#ifndef __VFSTABLENAME -#define __VFSTABLENAME g_FileSystemTable -#endif -#define vfsInitDirectory __VFSTABLENAME.m_pfnInitDirectory -#define vfsShutdown __VFSTABLENAME.m_pfnShutdown -#define vfsFreeFile __VFSTABLENAME.m_pfnFreeFile -#define vfsGetDirList __VFSTABLENAME.m_pfnGetDirList -#define vfsGetFileList __VFSTABLENAME.m_pfnGetFileList -#define vfsClearFileDirList __VFSTABLENAME.m_pfnClearFileDirList -#define vfsGetFileCount __VFSTABLENAME.m_pfnGetFileCount -#define vfsLoadFile __VFSTABLENAME.m_pfnLoadFile -#define vfsLoadFullPathFile __VFSTABLENAME.m_pfnLoadFullPathFile -#define vfsExtractRelativePath __VFSTABLENAME.m_pfnExtractRelativePath -#define vfsGetFullPath __VFSTABLENAME.m_pfnGetFullPath -#define vfsBasePromptPath __VFSTABLENAME.m_pfnBasePromptPath -#endif - -#endif // _IFILESYSTEM_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IFILESYSTEM_H_ +#define _IFILESYSTEM_H_ + +// +// Plugin interface for the virtual filesystem used by Radiant +// + +// NOTE: If you want to write a VFS plugin then you must export +// "QERPlug_ListInterfaces" and "QERPlug_RequestInterface" +// (see qerplugin.h for more information) + +#ifdef _WIN32 +#define VFS_NATIVESEPARATOR '\\' +#else +#define VFS_NATIVESEPARATOR '/' +#endif + +#define VFS_MAJOR "VFS" + +// return the file system supported by the plugin, for example: "quake1" or "quake3" +//typedef const char* (WINAPI* PFN_VFSGETFORMAT) (); +// add all files from a directory to the vfs +typedef void (* PFN_VFSINITDIRECTORY) (const char *path); +// free all resources used by the plugin +typedef void (* PFN_VFSSHUTDOWN) (); +// free memory allocated by VFS for this pointer +typedef void (* PFN_VFSFREEFILE) (void *p); +// return a GSList with all the directories under basedir +typedef GSList* (* PFN_VFSGETDIRLIST) (const char *basedir); +// return a GSList with all the files under basedir (extension can be NULL) +typedef GSList* (* PFN_VFSGETFILELIST) (const char *basedir, const char *extension); +// free a dirlist or filelist returned from one of the above functions +typedef void (* PFN_VFSCLEARFILEDIRLIST) (GSList **lst); +#define VFS_SEARCH_PAK 0x1 +#define VFS_SEARCH_DIR 0x2 +/*! +\brief return the number of files with the exact name described in filename +there can be several hits for a given file, or this can be used to check for existence +\param flags is optional and can be used with VFS_SEARCH_* bits, if flag is 0, everything is searched, else only the specified bits +paks are searched first, then search directories +*/ +typedef int (* PFN_VFSGETFILECOUNT) (const char *filename, int flags); +/*! +\brief load file, allocate buffer +\return -1 if fails or the size of the buffer allocated +\param index is used to load the i-th file in the search directories (see vfsGetFileCount) +this will scan in the search directories first, then it will search in the pak files +WARNING: the allocated buffer must be freed with a g_free call +NOTE TTimo: the g_free release is utter horror + see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 +*/ +typedef int (* PFN_VFSLOADFILE) (const char *filename, void **buffer, int index); +// load a file from it's full path into the buffer, returns the file size or -1 +// the allocated buffer must be freed with a g_free call +typedef int (* PFN_VFSLOADFULLPATHFILE) (const char *filename, void **buffer); +// takes an absolute file path, returns a shortened relative file path if the absolute path matches a valid basedir or NULL if an error occured +typedef char* (* PFN_VFSEXTRACTRELATIVEPATH) (const char *in); +/*! +\return the full path (in a static buff) to a file given it's relative path (NULL if not found) +\param index if several files are matching (as returned in a call to vfsGetFileCount), get the index-th file +\param flag 0 or a combination of VFS_SEARCH_PAK or VFS_SEARCH_DIR +HYDRA: + this now searches VFS/PAK files in addition to the filesystem + if FLAG is 0 then ONLY dirs are searched. + PAK's are searched before DIRs to mimic engine behaviour + index is ignored when searching PAK files. + when searching VFS, files are searched case insensitive. + +WARNING: if you use index from vfsGetFileCount, it works only with a vfsGetFileCount for the search directories only (not the pak files) +FIXME TTimo our VFS names are case insensitive. + this function is not able to build the full path from case-insensitive name + ( this is http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ) +*/ +typedef char* (* PFN_VFSGETFULLPATH) (const char *in, int index, int flag); +/*! +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. +FIXME: I'm not sure this is used / relevant anymore +*/ +typedef const char* (* PFN_VFSBASEPROMPTPATH) (); + +// VFS API +struct _QERFileSystemTable +{ + int m_nSize; + PFN_VFSINITDIRECTORY m_pfnInitDirectory; + PFN_VFSSHUTDOWN m_pfnShutdown; + PFN_VFSFREEFILE m_pfnFreeFile; + PFN_VFSGETDIRLIST m_pfnGetDirList; + PFN_VFSGETFILELIST m_pfnGetFileList; + PFN_VFSCLEARFILEDIRLIST m_pfnClearFileDirList; + PFN_VFSGETFILECOUNT m_pfnGetFileCount; + PFN_VFSLOADFILE m_pfnLoadFile; + PFN_VFSLOADFULLPATHFILE m_pfnLoadFullPathFile; + PFN_VFSEXTRACTRELATIVEPATH m_pfnExtractRelativePath; + PFN_VFSGETFULLPATH m_pfnGetFullPath; + PFN_VFSBASEPROMPTPATH m_pfnBasePromptPath; +}; + +#ifdef USE_VFSTABLE_DEFINE +#ifndef __VFSTABLENAME +#define __VFSTABLENAME g_FileSystemTable +#endif +#define vfsInitDirectory __VFSTABLENAME.m_pfnInitDirectory +#define vfsShutdown __VFSTABLENAME.m_pfnShutdown +#define vfsFreeFile __VFSTABLENAME.m_pfnFreeFile +#define vfsGetDirList __VFSTABLENAME.m_pfnGetDirList +#define vfsGetFileList __VFSTABLENAME.m_pfnGetFileList +#define vfsClearFileDirList __VFSTABLENAME.m_pfnClearFileDirList +#define vfsGetFileCount __VFSTABLENAME.m_pfnGetFileCount +#define vfsLoadFile __VFSTABLENAME.m_pfnLoadFile +#define vfsLoadFullPathFile __VFSTABLENAME.m_pfnLoadFullPathFile +#define vfsExtractRelativePath __VFSTABLENAME.m_pfnExtractRelativePath +#define vfsGetFullPath __VFSTABLENAME.m_pfnGetFullPath +#define vfsBasePromptPath __VFSTABLENAME.m_pfnBasePromptPath +#endif + +#endif // _IFILESYSTEM_H_ diff --git a/include/igl.h b/include/igl.h index 99e4141f..630d3d34 100644 --- a/include/igl.h +++ b/include/igl.h @@ -1,266 +1,266 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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: -// all purpose OpenGL interface for Q3Radiant plugins -// - -#ifndef __IGL_H__ -#define __IGL_H__ - -#if defined (__linux__) || defined (__APPLE__) -#include <GL/glx.h> -#endif - -// we use these classes to let plugins draw inside the Radiant windows -// 2D window like YZ XZ XY -class IGL2DWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - virtual void Draw2D( VIEWTYPE vt ) = 0; -}; - -// 3D window -class IGL3DWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - virtual void Draw3D() = 0; -}; - -#define QGL_MAJOR "qgl" - -#include <GL/gl.h> - -typedef void (APIENTRY* PFN_QGLALPHAFUNC) (GLenum func, GLclampf ref); -typedef void (APIENTRY* PFN_QGLBEGIN) (GLenum); -typedef void (APIENTRY* PFN_QGLBINDTEXTURE) (GLenum target, GLuint texture); -typedef void (APIENTRY* PFN_QGLBLENDFUNC) (GLenum sfactor, GLenum dfactor); -typedef void (APIENTRY* PFN_QGLCALLLIST) (GLuint list); -typedef void (APIENTRY* PFN_QGLCALLLISTS) (GLsizei n, GLenum type, const GLvoid *lists); -typedef void (APIENTRY* PFN_QGLCLEAR) (GLbitfield mask); -typedef void (APIENTRY* PFN_QGLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); -typedef void (APIENTRY* PFN_QGLCLEARDEPTH) (GLclampd depth); -typedef void (APIENTRY* PFN_QGLCOLOR3F) (GLfloat red, GLfloat green, GLfloat blue); -typedef void (APIENTRY* PFN_QGLCOLOR3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLCOLOR4F) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); -typedef void (APIENTRY* PFN_QGLCOLOR4FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLCOLOR4UBV) (const GLubyte *v); -typedef void (APIENTRY* PFN_QGLCOLORPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLCULLFACE) (GLenum mode); -typedef void (APIENTRY* PFN_QGLDELETELISTS) (GLuint list, GLsizei range); -typedef void (APIENTRY* PFN_QGLDELETETEXTURES) (GLsizei n, const GLuint *textures); -typedef void (APIENTRY* PFN_QGLDEPTHFUNC) (GLenum func); -typedef void (APIENTRY* PFN_QGLDEPTHMASK) (GLboolean flag); -typedef void (APIENTRY* PFN_QGLDISABLE) (GLenum cap); -typedef void (APIENTRY* PFN_QGLDISABLECLIENTSTATE) (GLenum array); -typedef void (APIENTRY* PFN_QGLDRAWELEMENTS) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); -typedef void (APIENTRY* PFN_QGLENABLE) (GLenum cap); -typedef void (APIENTRY* PFN_QGLENABLECLIENTSTATE) (GLenum array); -typedef void (APIENTRY* PFN_QGLEND) (); -typedef void (APIENTRY* PFN_QGLENDLIST) (); -typedef void (APIENTRY* PFN_QGLFOGF) (GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLFOGFV) (GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLFOGFI) (GLenum pname, GLint param); -typedef GLuint (APIENTRY* PFN_QGLGENLISTS) (GLsizei range); -typedef void (APIENTRY *PFN_QGLGENTEXTURES) (GLsizei n, GLuint *textures); -typedef void (APIENTRY* PFN_QGLGETDOUBLEV) (GLenum pname, GLdouble *params); -typedef void (APIENTRY* PFN_QGLHINT) (GLenum target, GLenum mode); -typedef void (APIENTRY* PFN_QGLGETINTEGERV) (GLenum pname, GLint *params); -typedef void (APIENTRY* PFN_QGLLIGHTFV) (GLenum light, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); -typedef void (APIENTRY* PFN_QGLLINESTIPPLE) (GLint factor, GLushort pattern); -typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); -typedef void (APIENTRY* PFN_QGLLISTBASE) (GLuint base); -typedef void (APIENTRY* PFN_QGLLOADIDENTITY) (); -typedef void (APIENTRY* PFN_QGLMATERIALF) (GLenum face, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLMATERIALFV) (GLenum face, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLMATRIXMODE) (GLenum mode); -typedef void (APIENTRY* PFN_QGLMULTMATRIXF) (const GLfloat *m); -typedef void (APIENTRY* PFN_QGLNEWLIST) (GLuint list, GLenum mode); -typedef void (APIENTRY* PFN_QGLNORMAL3F) (GLfloat nx, GLfloat ny, GLfloat nz); -typedef void (APIENTRY* PFN_QGLNORMAL3FV) (const GLfloat *n); -typedef void (APIENTRY* PFN_QGLNORMALPOINTER) (GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLORTHO) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRY* PFN_QGLPOINTSIZE) (GLfloat size); -typedef void (APIENTRY* PFN_QGLPOLYGONMODE) (GLenum face, GLenum mode); -typedef void (APIENTRY* PFN_QGLPOPATTRIB) (); -typedef void (APIENTRY* PFN_QGLPOPMATRIX) (); -typedef void (APIENTRY* PFN_QGLPUSHATTRIB) (GLbitfield mask); -typedef void (APIENTRY* PFN_QGLPUSHMATRIX) (); -typedef void (APIENTRY* PFN_QGLRASTERPOS3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLROTATED) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRY* PFN_QGLROTATEF) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSCISSOR) (GLint x, GLint y, GLsizei width, GLsizei height); -typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLSHADEMODEL) (GLenum mode); -typedef void (APIENTRY* PFN_QGLTEXCOORD2F) (GLfloat s, GLfloat t); -typedef void (APIENTRY* PFN_QGLTEXCOORD2FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLTEXCOORDPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLTEXENVF) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXGENF) (GLenum coord, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXIMAGE1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXIMAGE2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERF) (GLenum target, GLenum pname, GLfloat param); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERFV) (GLenum target, GLenum pname, const GLfloat *params); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERI) (GLenum target, GLenum pname, GLint param); -typedef void (APIENTRY* PFN_QGLTEXPARAMETERIV) (GLenum target, GLenum pname, const GLint *params); -typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); -typedef void (APIENTRY* PFN_QGLTRANSLATED) (GLdouble x, GLdouble y, GLdouble z); -typedef void (APIENTRY* PFN_QGLTRANSLATEF) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLVERTEX2F) (GLfloat x, GLfloat y); -typedef void (APIENTRY* PFN_QGLVERTEX3F) (GLfloat x, GLfloat y, GLfloat z); -typedef void (APIENTRY* PFN_QGLVERTEX3FV) (const GLfloat *v); -typedef void (APIENTRY* PFN_QGLVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); -typedef void (APIENTRY* PFN_QGLVIEWPORT) (GLint x, GLint y, GLsizei width, GLsizei height); - -typedef void (WINAPI* PFN_QE_CHECKOPENGLFORERRORS) (); - -// glu stuff -// TTimo: NOTE: relying on glu might not be such a good idea. On many systems, the GLU lib is outdated, misversioned etc. -typedef void (APIENTRY * PFN_QGLUPERSPECTIVE) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); -typedef void (APIENTRY * PFN_QGLULOOKAT) (GLdouble eyex, GLdouble eyey, GLdouble eyez, - GLdouble centerx, GLdouble centery, GLdouble centerz, - GLdouble upx, GLdouble upy, GLdouble upz); -//++timo gluErrorString is defined but not exposed in the IGL interface - - -// plugins drawing inside the GL windows -//++timo TODO: add hooking into other windows (Z and .. texture??) -//+timo NOTE: this could be moved to the messaging system instead of having a dedicated interface <- yet I don't know how -typedef void (WINAPI* PFN_QERAPP_HOOKGL2DWINDOW) (IGL2DWindow *); -typedef void (WINAPI* PFN_QERAPP_UNHOOKGL2DWINDOW) (IGL2DWindow *); -typedef void (WINAPI* PFN_QERAPP_HOOKGL3DWINDOW) (IGL3DWindow *); -typedef void (WINAPI* PFN_QERAPP_UNHOOKGL3DWINDOW) (IGL3DWindow *); - -struct _QERQglTable -{ - //++timo do we really wanna play with versions ? - // float m_fVersion; - int m_nSize; - PFN_QGLALPHAFUNC m_pfn_qglAlphaFunc; - PFN_QGLBEGIN m_pfn_qglBegin; - PFN_QGLBINDTEXTURE m_pfn_qglBindTexture; - PFN_QGLBLENDFUNC m_pfn_qglBlendFunc; - PFN_QGLCALLLIST m_pfn_qglCallList; - PFN_QGLCLEAR m_pfn_qglClear; - PFN_QGLCLEARCOLOR m_pfn_qglClearColor; - PFN_QGLCALLLISTS m_pfn_qglCallLists; - PFN_QGLCLEARDEPTH m_pfn_qglClearDepth; - PFN_QGLCOLOR3F m_pfn_qglColor3f; - PFN_QGLCOLOR3FV m_pfn_qglColor3fv; - PFN_QGLCOLOR4F m_pfn_qglColor4f; - PFN_QGLCOLOR4FV m_pfn_qglColor4fv; - PFN_QGLCOLOR4UBV m_pfn_qglColor4ubv; // ydnar - PFN_QGLCOLORPOINTER m_pfn_qglColorPointer; - PFN_QGLCULLFACE m_pfn_qglCullFace; - PFN_QGLDELETELISTS m_pfn_qglDeleteLists; - PFN_QGLDELETETEXTURES m_pfn_qglDeleteTextures; - PFN_QGLDEPTHFUNC m_pfn_qglDepthFunc; - PFN_QGLDEPTHMASK m_pfn_qglDepthMask; - PFN_QGLDISABLE m_pfn_qglDisable; - PFN_QGLDISABLECLIENTSTATE m_pfn_qglDisableClientState; - PFN_QGLDRAWELEMENTS m_pfn_qglDrawElements; - PFN_QGLENABLE m_pfn_qglEnable; - PFN_QGLENABLECLIENTSTATE m_pfn_qglEnableClientState; - PFN_QGLEND m_pfn_qglEnd; - PFN_QGLENDLIST m_pfn_qglEndList; - PFN_QGLFOGF m_pfn_qglFogf; - PFN_QGLFOGFV m_pfn_qglFogfv; - PFN_QGLFOGFI m_pfn_qglFogi; - PFN_QGLGENLISTS m_pfn_qglGenLists; - PFN_QGLGENTEXTURES m_pfn_qglGenTextures; - PFN_QGLGETDOUBLEV m_pfn_qglGetDoublev; - PFN_QGLGETINTEGERV m_pfn_qglGetIntegerv; - PFN_QGLHINT m_pfn_qglHint; - PFN_QGLLIGHTFV m_pfn_qglLightfv; - PFN_QGLLINESTIPPLE m_pfn_qglLineStipple; - PFN_QGLLINEWIDTH m_pfn_qglLineWidth; - PFN_QGLLISTBASE m_pfn_qglListBase; - PFN_QGLLOADIDENTITY m_pfn_qglLoadIdentity; - PFN_QGLMATERIALF m_pfn_qglMaterialf; - PFN_QGLMATERIALFV m_pfn_qglMaterialfv; - PFN_QGLMATRIXMODE m_pfn_qglMatrixMode; - PFN_QGLMULTMATRIXF m_pfn_qglMultMatrixf; - PFN_QGLNEWLIST m_pfn_qglNewList; - PFN_QGLNORMAL3F m_pfn_qglNormal3f; - PFN_QGLNORMAL3FV m_pfn_qglNormal3fv; - PFN_QGLNORMALPOINTER m_pfn_qglNormalPointer; - PFN_QGLORTHO m_pfn_qglOrtho; - PFN_QGLPOINTSIZE m_pfn_qglPointSize; - PFN_QGLPOLYGONMODE m_pfn_qglPolygonMode; - PFN_QGLPOPATTRIB m_pfn_qglPopAttrib; - PFN_QGLPOPMATRIX m_pfn_qglPopMatrix; - PFN_QGLPUSHATTRIB m_pfn_qglPushAttrib; - PFN_QGLPUSHMATRIX m_pfn_qglPushMatrix; - PFN_QGLRASTERPOS3FV m_pfn_qglRasterPos3fv; - PFN_QGLROTATED m_pfn_qglRotated; - PFN_QGLROTATEF m_pfn_qglRotatef; - PFN_QGLSCALEF m_pfn_qglScalef; - PFN_QGLSCISSOR m_pfn_qglScissor; - PFN_QGLSHADEMODEL m_pfn_qglShadeModel; - PFN_QGLTEXCOORD2F m_pfn_qglTexCoord2f; - PFN_QGLTEXCOORD2FV m_pfn_qglTexCoord2fv; - PFN_QGLTEXCOORDPOINTER m_pfn_qglTexCoordPointer; - PFN_QGLTEXENVF m_pfn_qglTexEnvf; - PFN_QGLTEXGENF m_pfn_qglTexGenf; - PFN_QGLTEXIMAGE1D m_pfn_qglTexImage1D; - PFN_QGLTEXIMAGE2D m_pfn_qglTexImage2D; - PFN_QGLTEXPARAMETERF m_pfn_qglTexParameterf; - PFN_QGLTEXPARAMETERFV m_pfn_qglTexParameterfv; - PFN_QGLTEXPARAMETERI m_pfn_qglTexParameteri; - PFN_QGLTEXPARAMETERIV m_pfn_qglTexParameteriv; - PFN_QGLTEXSUBIMAGE1D m_pfn_qglTexSubImage1D; - PFN_QGLTEXSUBIMAGE2D m_pfn_qglTexSubImage2D; - PFN_QGLTRANSLATED m_pfn_qglTranslated; - PFN_QGLTRANSLATEF m_pfn_qglTranslatef; - PFN_QGLVERTEX2F m_pfn_qglVertex2f; - PFN_QGLVERTEX3F m_pfn_qglVertex3f; - PFN_QGLVERTEX3FV m_pfn_qglVertex3fv; - PFN_QGLVERTEXPOINTER m_pfn_qglVertexPointer; - PFN_QGLVIEWPORT m_pfn_qglViewport; - - PFN_QE_CHECKOPENGLFORERRORS m_pfn_QE_CheckOpenGLForErrors; - - // glu stuff - PFN_QGLUPERSPECTIVE m_pfn_qgluPerspective; - PFN_QGLULOOKAT m_pfn_qgluLookAt; - - // plugin entities drawing inside Radiant windows - PFN_QERAPP_HOOKGL2DWINDOW m_pfnHookGL2DWindow; - PFN_QERAPP_UNHOOKGL2DWINDOW m_pfnUnHookGL2DWindow; - PFN_QERAPP_HOOKGL3DWINDOW m_pfnHookGL3DWindow; - PFN_QERAPP_UNHOOKGL3DWINDOW m_pfnUnHookGL3DWindow; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// all purpose OpenGL interface for Q3Radiant plugins +// + +#ifndef __IGL_H__ +#define __IGL_H__ + +#if defined (__linux__) || defined (__APPLE__) +#include <GL/glx.h> +#endif + +// we use these classes to let plugins draw inside the Radiant windows +// 2D window like YZ XZ XY +class IGL2DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw2D( VIEWTYPE vt ) = 0; +}; + +// 3D window +class IGL3DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw3D() = 0; +}; + +#define QGL_MAJOR "qgl" + +#include <GL/gl.h> + +typedef void (APIENTRY* PFN_QGLALPHAFUNC) (GLenum func, GLclampf ref); +typedef void (APIENTRY* PFN_QGLBEGIN) (GLenum); +typedef void (APIENTRY* PFN_QGLBINDTEXTURE) (GLenum target, GLuint texture); +typedef void (APIENTRY* PFN_QGLBLENDFUNC) (GLenum sfactor, GLenum dfactor); +typedef void (APIENTRY* PFN_QGLCALLLIST) (GLuint list); +typedef void (APIENTRY* PFN_QGLCALLLISTS) (GLsizei n, GLenum type, const GLvoid *lists); +typedef void (APIENTRY* PFN_QGLCLEAR) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (APIENTRY* PFN_QGLCLEARDEPTH) (GLclampd depth); +typedef void (APIENTRY* PFN_QGLCOLOR3F) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRY* PFN_QGLCOLOR3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4F) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRY* PFN_QGLCOLOR4FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4UBV) (const GLubyte *v); +typedef void (APIENTRY* PFN_QGLCOLORPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLCULLFACE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLDELETELISTS) (GLuint list, GLsizei range); +typedef void (APIENTRY* PFN_QGLDELETETEXTURES) (GLsizei n, const GLuint *textures); +typedef void (APIENTRY* PFN_QGLDEPTHFUNC) (GLenum func); +typedef void (APIENTRY* PFN_QGLDEPTHMASK) (GLboolean flag); +typedef void (APIENTRY* PFN_QGLDISABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLDISABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLDRAWELEMENTS) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRY* PFN_QGLENABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLENABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLEND) (); +typedef void (APIENTRY* PFN_QGLENDLIST) (); +typedef void (APIENTRY* PFN_QGLFOGF) (GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLFOGFV) (GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLFOGFI) (GLenum pname, GLint param); +typedef GLuint (APIENTRY* PFN_QGLGENLISTS) (GLsizei range); +typedef void (APIENTRY *PFN_QGLGENTEXTURES) (GLsizei n, GLuint *textures); +typedef void (APIENTRY* PFN_QGLGETDOUBLEV) (GLenum pname, GLdouble *params); +typedef void (APIENTRY* PFN_QGLHINT) (GLenum target, GLenum mode); +typedef void (APIENTRY* PFN_QGLGETINTEGERV) (GLenum pname, GLint *params); +typedef void (APIENTRY* PFN_QGLLIGHTFV) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLINESTIPPLE) (GLint factor, GLushort pattern); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLISTBASE) (GLuint base); +typedef void (APIENTRY* PFN_QGLLOADIDENTITY) (); +typedef void (APIENTRY* PFN_QGLMATERIALF) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLMATERIALFV) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLMATRIXMODE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLMULTMATRIXF) (const GLfloat *m); +typedef void (APIENTRY* PFN_QGLNEWLIST) (GLuint list, GLenum mode); +typedef void (APIENTRY* PFN_QGLNORMAL3F) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRY* PFN_QGLNORMAL3FV) (const GLfloat *n); +typedef void (APIENTRY* PFN_QGLNORMALPOINTER) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLORTHO) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY* PFN_QGLPOINTSIZE) (GLfloat size); +typedef void (APIENTRY* PFN_QGLPOLYGONMODE) (GLenum face, GLenum mode); +typedef void (APIENTRY* PFN_QGLPOPATTRIB) (); +typedef void (APIENTRY* PFN_QGLPOPMATRIX) (); +typedef void (APIENTRY* PFN_QGLPUSHATTRIB) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLPUSHMATRIX) (); +typedef void (APIENTRY* PFN_QGLRASTERPOS3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLROTATED) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLROTATEF) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCISSOR) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSHADEMODEL) (GLenum mode); +typedef void (APIENTRY* PFN_QGLTEXCOORD2F) (GLfloat s, GLfloat t); +typedef void (APIENTRY* PFN_QGLTEXCOORD2FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLTEXCOORDPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLTEXENVF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXGENF) (GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXIMAGE1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXIMAGE2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERFV) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERI) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERIV) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTRANSLATED) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLTRANSLATEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX2F) (GLfloat x, GLfloat y); +typedef void (APIENTRY* PFN_QGLVERTEX3F) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLVIEWPORT) (GLint x, GLint y, GLsizei width, GLsizei height); + +typedef void (WINAPI* PFN_QE_CHECKOPENGLFORERRORS) (); + +// glu stuff +// TTimo: NOTE: relying on glu might not be such a good idea. On many systems, the GLU lib is outdated, misversioned etc. +typedef void (APIENTRY * PFN_QGLUPERSPECTIVE) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY * PFN_QGLULOOKAT) (GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz); +//++timo gluErrorString is defined but not exposed in the IGL interface + + +// plugins drawing inside the GL windows +//++timo TODO: add hooking into other windows (Z and .. texture??) +//+timo NOTE: this could be moved to the messaging system instead of having a dedicated interface <- yet I don't know how +typedef void (WINAPI* PFN_QERAPP_HOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_HOOKGL3DWINDOW) (IGL3DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL3DWINDOW) (IGL3DWindow *); + +struct _QERQglTable +{ + //++timo do we really wanna play with versions ? + // float m_fVersion; + int m_nSize; + PFN_QGLALPHAFUNC m_pfn_qglAlphaFunc; + PFN_QGLBEGIN m_pfn_qglBegin; + PFN_QGLBINDTEXTURE m_pfn_qglBindTexture; + PFN_QGLBLENDFUNC m_pfn_qglBlendFunc; + PFN_QGLCALLLIST m_pfn_qglCallList; + PFN_QGLCLEAR m_pfn_qglClear; + PFN_QGLCLEARCOLOR m_pfn_qglClearColor; + PFN_QGLCALLLISTS m_pfn_qglCallLists; + PFN_QGLCLEARDEPTH m_pfn_qglClearDepth; + PFN_QGLCOLOR3F m_pfn_qglColor3f; + PFN_QGLCOLOR3FV m_pfn_qglColor3fv; + PFN_QGLCOLOR4F m_pfn_qglColor4f; + PFN_QGLCOLOR4FV m_pfn_qglColor4fv; + PFN_QGLCOLOR4UBV m_pfn_qglColor4ubv; // ydnar + PFN_QGLCOLORPOINTER m_pfn_qglColorPointer; + PFN_QGLCULLFACE m_pfn_qglCullFace; + PFN_QGLDELETELISTS m_pfn_qglDeleteLists; + PFN_QGLDELETETEXTURES m_pfn_qglDeleteTextures; + PFN_QGLDEPTHFUNC m_pfn_qglDepthFunc; + PFN_QGLDEPTHMASK m_pfn_qglDepthMask; + PFN_QGLDISABLE m_pfn_qglDisable; + PFN_QGLDISABLECLIENTSTATE m_pfn_qglDisableClientState; + PFN_QGLDRAWELEMENTS m_pfn_qglDrawElements; + PFN_QGLENABLE m_pfn_qglEnable; + PFN_QGLENABLECLIENTSTATE m_pfn_qglEnableClientState; + PFN_QGLEND m_pfn_qglEnd; + PFN_QGLENDLIST m_pfn_qglEndList; + PFN_QGLFOGF m_pfn_qglFogf; + PFN_QGLFOGFV m_pfn_qglFogfv; + PFN_QGLFOGFI m_pfn_qglFogi; + PFN_QGLGENLISTS m_pfn_qglGenLists; + PFN_QGLGENTEXTURES m_pfn_qglGenTextures; + PFN_QGLGETDOUBLEV m_pfn_qglGetDoublev; + PFN_QGLGETINTEGERV m_pfn_qglGetIntegerv; + PFN_QGLHINT m_pfn_qglHint; + PFN_QGLLIGHTFV m_pfn_qglLightfv; + PFN_QGLLINESTIPPLE m_pfn_qglLineStipple; + PFN_QGLLINEWIDTH m_pfn_qglLineWidth; + PFN_QGLLISTBASE m_pfn_qglListBase; + PFN_QGLLOADIDENTITY m_pfn_qglLoadIdentity; + PFN_QGLMATERIALF m_pfn_qglMaterialf; + PFN_QGLMATERIALFV m_pfn_qglMaterialfv; + PFN_QGLMATRIXMODE m_pfn_qglMatrixMode; + PFN_QGLMULTMATRIXF m_pfn_qglMultMatrixf; + PFN_QGLNEWLIST m_pfn_qglNewList; + PFN_QGLNORMAL3F m_pfn_qglNormal3f; + PFN_QGLNORMAL3FV m_pfn_qglNormal3fv; + PFN_QGLNORMALPOINTER m_pfn_qglNormalPointer; + PFN_QGLORTHO m_pfn_qglOrtho; + PFN_QGLPOINTSIZE m_pfn_qglPointSize; + PFN_QGLPOLYGONMODE m_pfn_qglPolygonMode; + PFN_QGLPOPATTRIB m_pfn_qglPopAttrib; + PFN_QGLPOPMATRIX m_pfn_qglPopMatrix; + PFN_QGLPUSHATTRIB m_pfn_qglPushAttrib; + PFN_QGLPUSHMATRIX m_pfn_qglPushMatrix; + PFN_QGLRASTERPOS3FV m_pfn_qglRasterPos3fv; + PFN_QGLROTATED m_pfn_qglRotated; + PFN_QGLROTATEF m_pfn_qglRotatef; + PFN_QGLSCALEF m_pfn_qglScalef; + PFN_QGLSCISSOR m_pfn_qglScissor; + PFN_QGLSHADEMODEL m_pfn_qglShadeModel; + PFN_QGLTEXCOORD2F m_pfn_qglTexCoord2f; + PFN_QGLTEXCOORD2FV m_pfn_qglTexCoord2fv; + PFN_QGLTEXCOORDPOINTER m_pfn_qglTexCoordPointer; + PFN_QGLTEXENVF m_pfn_qglTexEnvf; + PFN_QGLTEXGENF m_pfn_qglTexGenf; + PFN_QGLTEXIMAGE1D m_pfn_qglTexImage1D; + PFN_QGLTEXIMAGE2D m_pfn_qglTexImage2D; + PFN_QGLTEXPARAMETERF m_pfn_qglTexParameterf; + PFN_QGLTEXPARAMETERFV m_pfn_qglTexParameterfv; + PFN_QGLTEXPARAMETERI m_pfn_qglTexParameteri; + PFN_QGLTEXPARAMETERIV m_pfn_qglTexParameteriv; + PFN_QGLTEXSUBIMAGE1D m_pfn_qglTexSubImage1D; + PFN_QGLTEXSUBIMAGE2D m_pfn_qglTexSubImage2D; + PFN_QGLTRANSLATED m_pfn_qglTranslated; + PFN_QGLTRANSLATEF m_pfn_qglTranslatef; + PFN_QGLVERTEX2F m_pfn_qglVertex2f; + PFN_QGLVERTEX3F m_pfn_qglVertex3f; + PFN_QGLVERTEX3FV m_pfn_qglVertex3fv; + PFN_QGLVERTEXPOINTER m_pfn_qglVertexPointer; + PFN_QGLVIEWPORT m_pfn_qglViewport; + + PFN_QE_CHECKOPENGLFORERRORS m_pfn_QE_CheckOpenGLForErrors; + + // glu stuff + PFN_QGLUPERSPECTIVE m_pfn_qgluPerspective; + PFN_QGLULOOKAT m_pfn_qgluLookAt; + + // plugin entities drawing inside Radiant windows + PFN_QERAPP_HOOKGL2DWINDOW m_pfnHookGL2DWindow; + PFN_QERAPP_UNHOOKGL2DWINDOW m_pfnUnHookGL2DWindow; + PFN_QERAPP_HOOKGL3DWINDOW m_pfnHookGL3DWindow; + PFN_QERAPP_UNHOOKGL3DWINDOW m_pfnUnHookGL3DWindow; +}; + +#endif diff --git a/include/iimage.h b/include/iimage.h index e473c4fe..6335082b 100644 --- a/include/iimage.h +++ b/include/iimage.h @@ -1,40 +1,40 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// Plugin interface for loading image files -// - -#ifndef _IIMAGE_H_ -#define _IIMAGE_H_ - -#define IMAGE_MAJOR "image" - -// Load an image file -typedef void (* PFN_QERPLUG_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); - -struct _QERPlugImageTable -{ - int m_nSize; - PFN_QERPLUG_LOADIMAGE m_pfnLoadImage; -}; - -#endif // _IIMAGE_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Plugin interface for loading image files +// + +#ifndef _IIMAGE_H_ +#define _IIMAGE_H_ + +#define IMAGE_MAJOR "image" + +// Load an image file +typedef void (* PFN_QERPLUG_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +struct _QERPlugImageTable +{ + int m_nSize; + PFN_QERPLUG_LOADIMAGE m_pfnLoadImage; +}; + +#endif // _IIMAGE_H_ diff --git a/include/imap.h b/include/imap.h index 230d5dd1..cddbadf7 100644 --- a/include/imap.h +++ b/include/imap.h @@ -1,82 +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 -*/ - -//---------------------------------------------------------------------------- -// -// DESCRIPTION: -// map format interface (.map and .xmap, Q3 and other games) -// - -#ifndef __IMAP_H__ -#define __IMAP_H__ - -/*! IMap depends on IDataStream, including the header there for now */ -#include "idatastream.h" - -/*! header for CPtrArray */ -#include "missing.h" - -#define MAP_MAJOR "map" -/*! -define a GUID for this interface so everyone can acces and reference it -{75076973-3414-49c9-be5b-2378ec5601af} -*/ -static const GUID QERPlugMapTable_GUID = -{ 0x75076973, 0x3414, 0x49c9, { 0xbe, 0x5b, 0x23, 0x78, 0xec, 0x56, 0x01, 0xaf } }; - -/*! -read from a stream into a list of entities -\param in the input stream. For regular map file parsing it's possible to copy the content in a text buffer -and use the old school parser -\param ents the list of entities read from the stream. They are not linked to the world, and their brushes -are not either. -*/ -typedef void (* PFN_MAP_READ) (IDataStream *in, CPtrArray *ents); ///< read from a stream into a list of entities -typedef void (* PFN_MAP_WRITE) (CPtrArray *ents, IDataStream *out); ///< save a list of entities into a stream - -struct _QERPlugMapTable -{ - int m_nSize; - PFN_MAP_READ m_pfnMap_Read; - PFN_MAP_WRITE m_pfnMap_Write; -}; - -/*! -this set of macros will define the functions to map on a given table - it should be used in the headers (see modules source, plugin.h) -we don't want those defines in the part where WE implement the Map_LoadFile - so we're using a define to disable .. should find a standard define name - (for instance QCOM_CLIENT / QCOM_SERVER ?) - or the name should be specific to any interface .. it's not a client/server thing here anyway -*/ -#ifdef USE_MAPTABLE_DEFINE -#ifndef __MAPTABLENAME -/*! -TTimo NOTE: this is the default table name we map to - if you are using a different table name, just define __MAPTABLENAME before you include the imap.h header -*/ -#define __MAPTABLENAME g_MapTable -#endif -#define Map_Read __MAPTABLENAME.m_pfnMap_Read -#define Map_Write __MAPTABLENAME.m_pfnMap_Write -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// map format interface (.map and .xmap, Q3 and other games) +// + +#ifndef __IMAP_H__ +#define __IMAP_H__ + +/*! IMap depends on IDataStream, including the header there for now */ +#include "idatastream.h" + +/*! header for CPtrArray */ +#include "missing.h" + +#define MAP_MAJOR "map" +/*! +define a GUID for this interface so everyone can acces and reference it +{75076973-3414-49c9-be5b-2378ec5601af} +*/ +static const GUID QERPlugMapTable_GUID = +{ 0x75076973, 0x3414, 0x49c9, { 0xbe, 0x5b, 0x23, 0x78, 0xec, 0x56, 0x01, 0xaf } }; + +/*! +read from a stream into a list of entities +\param in the input stream. For regular map file parsing it's possible to copy the content in a text buffer +and use the old school parser +\param ents the list of entities read from the stream. They are not linked to the world, and their brushes +are not either. +*/ +typedef void (* PFN_MAP_READ) (IDataStream *in, CPtrArray *ents); ///< read from a stream into a list of entities +typedef void (* PFN_MAP_WRITE) (CPtrArray *ents, IDataStream *out); ///< save a list of entities into a stream + +struct _QERPlugMapTable +{ + int m_nSize; + PFN_MAP_READ m_pfnMap_Read; + PFN_MAP_WRITE m_pfnMap_Write; +}; + +/*! +this set of macros will define the functions to map on a given table + it should be used in the headers (see modules source, plugin.h) +we don't want those defines in the part where WE implement the Map_LoadFile + so we're using a define to disable .. should find a standard define name + (for instance QCOM_CLIENT / QCOM_SERVER ?) + or the name should be specific to any interface .. it's not a client/server thing here anyway +*/ +#ifdef USE_MAPTABLE_DEFINE +#ifndef __MAPTABLENAME +/*! +TTimo NOTE: this is the default table name we map to + if you are using a different table name, just define __MAPTABLENAME before you include the imap.h header +*/ +#define __MAPTABLENAME g_MapTable +#endif +#define Map_Read __MAPTABLENAME.m_pfnMap_Read +#define Map_Write __MAPTABLENAME.m_pfnMap_Write +#endif + +#endif diff --git a/include/imodel.h b/include/imodel.h index de5964a8..3dead05e 100644 --- a/include/imodel.h +++ b/include/imodel.h @@ -1,106 +1,106 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IMODEL_H_ -#define _IMODEL_H_ - -#define MODEL_MAJOR "model" - -/*! -loads model from model file name specified, -fills model struct with pointers to model interfaces - -name is a relative path, we'll use VFS to extract a basepath to add to get the absolute path. -*/ -typedef void (* PFN_LOADMODEL) (entity_interfaces_t *model, const char *name); - -struct _QERPlugModelTable -{ - int m_nSize; - PFN_LOADMODEL m_pfnLoadModel; -}; - - -//forward declare entity_t -struct entity_s; -typedef struct entity_s entity_t; - -// any module relying on imodel will need to link against the mathlib -#include "mathlib.h" - -// state flags -#define DRAW_GL_FILL 0x0001 -#define DRAW_GL_LIGHTING 0x0010 -#define DRAW_GL_TEXTURE_2D 0x0100 -#define DRAW_GL_BLEND 0x1000 - -// predefined state combinations -#define DRAW_GL_WIRE 0x0000 -#define DRAW_GL_FLAT 0x0001 -#define DRAW_GL_SOLID 0x0011 -#define DRAW_GL_TEXTURED 0x0111 - -// mode -#define DRAW_WIRE 0 -#define DRAW_SOLID 1 -#define DRAW_TEXTURED 2 - -// render flags -#define DRAW_RF_NONE 0x0000 -#define DRAW_RF_SEL_OUTLINE 0x0001 -#define DRAW_RF_SEL_FILL 0x0010 -#define DRAW_RF_XY 0x0011 -#define DRAW_RF_CAM 0x0100 - -class IRender -{ -public: - virtual ~IRender() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual void Draw(int state, int rflags) const = 0; // render the object - state = the opengl state - virtual const aabb_t *GetAABB() const = 0; -}; - -class ISelect -{ -public: - virtual ~ISelect() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual bool TestRay(const ray_t *ray, vec_t *dist) const = 0; // test ray intersection, return bool true if intersects, and store distance to closest point of intersection - //virtual bool TestBox(const aabb_t *aabb) const = 0; // test aabb intersection, return bool true if touching or intersecting -}; - -class IEdit -{ -public: - virtual ~IEdit() { } - virtual void IncRef() = 0; // increments the reference counter for this object - virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero - virtual void Translate(const vec3_t translation) = 0; - virtual void Rotate(const vec3_t pivot, const vec3_t rotation) = 0; - virtual const vec_t *GetTranslation() const = 0; - virtual const vec_t *GetRotation() const = 0; - virtual void OnKeyValueChanged(entity_t *e, const char *key, const char* value) = 0; -}; - -#endif /* _IMODEL_H_ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IMODEL_H_ +#define _IMODEL_H_ + +#define MODEL_MAJOR "model" + +/*! +loads model from model file name specified, +fills model struct with pointers to model interfaces + +name is a relative path, we'll use VFS to extract a basepath to add to get the absolute path. +*/ +typedef void (* PFN_LOADMODEL) (entity_interfaces_t *model, const char *name); + +struct _QERPlugModelTable +{ + int m_nSize; + PFN_LOADMODEL m_pfnLoadModel; +}; + + +//forward declare entity_t +struct entity_s; +typedef struct entity_s entity_t; + +// any module relying on imodel will need to link against the mathlib +#include "mathlib.h" + +// state flags +#define DRAW_GL_FILL 0x0001 +#define DRAW_GL_LIGHTING 0x0010 +#define DRAW_GL_TEXTURE_2D 0x0100 +#define DRAW_GL_BLEND 0x1000 + +// predefined state combinations +#define DRAW_GL_WIRE 0x0000 +#define DRAW_GL_FLAT 0x0001 +#define DRAW_GL_SOLID 0x0011 +#define DRAW_GL_TEXTURED 0x0111 + +// mode +#define DRAW_WIRE 0 +#define DRAW_SOLID 1 +#define DRAW_TEXTURED 2 + +// render flags +#define DRAW_RF_NONE 0x0000 +#define DRAW_RF_SEL_OUTLINE 0x0001 +#define DRAW_RF_SEL_FILL 0x0010 +#define DRAW_RF_XY 0x0011 +#define DRAW_RF_CAM 0x0100 + +class IRender +{ +public: + virtual ~IRender() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Draw(int state, int rflags) const = 0; // render the object - state = the opengl state + virtual const aabb_t *GetAABB() const = 0; +}; + +class ISelect +{ +public: + virtual ~ISelect() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual bool TestRay(const ray_t *ray, vec_t *dist) const = 0; // test ray intersection, return bool true if intersects, and store distance to closest point of intersection + //virtual bool TestBox(const aabb_t *aabb) const = 0; // test aabb intersection, return bool true if touching or intersecting +}; + +class IEdit +{ +public: + virtual ~IEdit() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Translate(const vec3_t translation) = 0; + virtual void Rotate(const vec3_t pivot, const vec3_t rotation) = 0; + virtual const vec_t *GetTranslation() const = 0; + virtual const vec_t *GetRotation() const = 0; + virtual void OnKeyValueChanged(entity_t *e, const char *key, const char* value) = 0; +}; + +#endif /* _IMODEL_H_ */ diff --git a/include/ipatch.h b/include/ipatch.h index ccfd39ed..300a0a75 100644 --- a/include/ipatch.h +++ b/include/ipatch.h @@ -1,53 +1,53 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IPATCH_H_ -#define _IPATCH_H_ - -// -// API for patch stuff -// - -#define PATCH_MAJOR "patch" -// {4715565b-ab3a-49fa-841f-ee965b6d88a5} -static const GUID QERPatchTable_GUID = -{ 0x4715565b, 0xab3a, 0x49fa, { 0x84, 0x1f, 0xee, 0x96, 0x5b, 0x6d, 0x88, 0xa5 } }; - -typedef patchMesh_t* (* PFN_PATCHALLOC) (); -typedef patchMesh_t* (* PFN_MAKENEWPATCH) (); -typedef brush_t* (* PFN_ADDBRUSHFORPATCH) (patchMesh_t *pm, bool bLinkToWorld ); - -struct _QERPatchTable -{ - int m_nSize; - PFN_PATCHALLOC m_pfnPatch_Alloc; - PFN_MAKENEWPATCH m_pfnMakeNewPatch; - PFN_ADDBRUSHFORPATCH m_pfnAddBrushForPatch; -}; - -#ifdef USE_PATCHTABLE_DEFINE -#define __PATCHTABLENAME g_PatchTable -#define Patch_Alloc __PATCHTABLENAME.m_pfnPatch_Alloc -#define MakeNewPatch __PATCHTABLENAME.m_pfnMakeNewPatch -#define AddBrushForPatch __PATCHTABLENAME.m_pfnAddBrushForPatch -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IPATCH_H_ +#define _IPATCH_H_ + +// +// API for patch stuff +// + +#define PATCH_MAJOR "patch" +// {4715565b-ab3a-49fa-841f-ee965b6d88a5} +static const GUID QERPatchTable_GUID = +{ 0x4715565b, 0xab3a, 0x49fa, { 0x84, 0x1f, 0xee, 0x96, 0x5b, 0x6d, 0x88, 0xa5 } }; + +typedef patchMesh_t* (* PFN_PATCHALLOC) (); +typedef patchMesh_t* (* PFN_MAKENEWPATCH) (); +typedef brush_t* (* PFN_ADDBRUSHFORPATCH) (patchMesh_t *pm, bool bLinkToWorld ); + +struct _QERPatchTable +{ + int m_nSize; + PFN_PATCHALLOC m_pfnPatch_Alloc; + PFN_MAKENEWPATCH m_pfnMakeNewPatch; + PFN_ADDBRUSHFORPATCH m_pfnAddBrushForPatch; +}; + +#ifdef USE_PATCHTABLE_DEFINE +#define __PATCHTABLENAME g_PatchTable +#define Patch_Alloc __PATCHTABLENAME.m_pfnPatch_Alloc +#define MakeNewPatch __PATCHTABLENAME.m_pfnMakeNewPatch +#define AddBrushForPatch __PATCHTABLENAME.m_pfnAddBrushForPatch +#endif + +#endif diff --git a/include/iplugin.h b/include/iplugin.h index e2974b9b..3f21bfef 100644 --- a/include/iplugin.h +++ b/include/iplugin.h @@ -1,41 +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 -*/ - -#ifndef _IPLUGIN_H_ -#define _IPLUGIN_H_ - -#define PLUGIN_MAJOR "plugin" - -typedef const char* (* PFN_QERPLUG_INIT) (void* hApp, void* pMainWidget); -typedef const char* (* PFN_QERPLUG_GETNAME) (); -typedef const char* (* PFN_QERPLUG_GETCOMMANDLIST) (); -typedef void (* PFN_QERPLUG_DISPATCH) (const char* p, float* vMin, float* vMax, bool bSingleBrush); - -struct _QERPluginTable -{ - int m_nSize; - PFN_QERPLUG_INIT m_pfnQERPlug_Init; - PFN_QERPLUG_GETNAME m_pfnQERPlug_GetName; - PFN_QERPLUG_GETCOMMANDLIST m_pfnQERPlug_GetCommandList; - PFN_QERPLUG_DISPATCH m_pfnQERPlug_Dispatch; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IPLUGIN_H_ +#define _IPLUGIN_H_ + +#define PLUGIN_MAJOR "plugin" + +typedef const char* (* PFN_QERPLUG_INIT) (void* hApp, void* pMainWidget); +typedef const char* (* PFN_QERPLUG_GETNAME) (); +typedef const char* (* PFN_QERPLUG_GETCOMMANDLIST) (); +typedef void (* PFN_QERPLUG_DISPATCH) (const char* p, float* vMin, float* vMax, bool bSingleBrush); + +struct _QERPluginTable +{ + int m_nSize; + PFN_QERPLUG_INIT m_pfnQERPlug_Init; + PFN_QERPLUG_GETNAME m_pfnQERPlug_GetName; + PFN_QERPLUG_GETCOMMANDLIST m_pfnQERPlug_GetCommandList; + PFN_QERPLUG_DISPATCH m_pfnQERPlug_Dispatch; +}; + +#endif diff --git a/include/irefcount.h b/include/irefcount.h index 2fc495ad..e49e80d7 100644 --- a/include/irefcount.h +++ b/include/irefcount.h @@ -1,62 +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 __IREFCOUNT_H__ -#define __IREFCOUNT_H__ - -/*! -\class IRefCounted -\brief reference counted objects - -general hints: how to use ref count properly - we consider ref counting as an extension of new and delete operators - the main issue is 'when to incref' 'when to decref' - in most cases connected to function calls - the general thinking about that: - - if you get a pointer to a refcounted object through a call to a function, assume that this object has been 'reserved' for you - already (i.e. allocated if you think this the new/delete way). so if you keep the object, you don't need to incref it, and if - you don't keep it you need to decref it. - - if you are called in a function and a refcounted object passed as parameter, then you should assume that this is an optional - object given to you FYI, which you don't need to decref if you don't keep / need to incref if you keep - - refcount is initialized to 1 in constructor. that serves for static objects and memory allocator - when you allocate in memory a ref counted object, it's default ref count will be 1, you should never delete it but just call DecRef on it - -define an interface and an implementation macro to make things easier -NOTE: we may have to provide a static library to go with that - in case we would move irecount.h out of here into libs/ - -\todo functionality needed: -mostly enable/disable some features with compile time flags (independently from each other as much as possible) -- log the destructor calls with != 0 ref count -- log all incref/decref (with module info, and maybe even file/line number etc.?) -*/ -class IRefCounted -{ - int refCount; -public: - IRefCounted() { refCount = 1; } - virtual ~IRefCounted() { } - void IncRef() { refCount++; } - void DecRef() { refCount--; if (refCount <= 0) delete this; } -}; - -#endif // __ISYNAPSE_H__ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __IREFCOUNT_H__ +#define __IREFCOUNT_H__ + +/*! +\class IRefCounted +\brief reference counted objects + +general hints: how to use ref count properly + we consider ref counting as an extension of new and delete operators + the main issue is 'when to incref' 'when to decref' + in most cases connected to function calls + the general thinking about that: + - if you get a pointer to a refcounted object through a call to a function, assume that this object has been 'reserved' for you + already (i.e. allocated if you think this the new/delete way). so if you keep the object, you don't need to incref it, and if + you don't keep it you need to decref it. + - if you are called in a function and a refcounted object passed as parameter, then you should assume that this is an optional + object given to you FYI, which you don't need to decref if you don't keep / need to incref if you keep + + refcount is initialized to 1 in constructor. that serves for static objects and memory allocator + when you allocate in memory a ref counted object, it's default ref count will be 1, you should never delete it but just call DecRef on it + +define an interface and an implementation macro to make things easier +NOTE: we may have to provide a static library to go with that + in case we would move irecount.h out of here into libs/ + +\todo functionality needed: +mostly enable/disable some features with compile time flags (independently from each other as much as possible) +- log the destructor calls with != 0 ref count +- log all incref/decref (with module info, and maybe even file/line number etc.?) +*/ +class IRefCounted +{ + int refCount; +public: + IRefCounted() { refCount = 1; } + virtual ~IRefCounted() { } + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } +}; + +#endif // __ISYNAPSE_H__ diff --git a/include/iscriplib.h b/include/iscriplib.h index 00ba6617..30b9bd8a 100644 --- a/include/iscriplib.h +++ b/include/iscriplib.h @@ -1,86 +1,86 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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: -// all purpose scriplib interface for Q3Radiant plugins (cf. parse.h) -// - -#ifndef __ISCRIPLIB_H_ -#define __ISCRIPLIB_H_ - -/*! \file iscriplib.h - \brief function tables for Radiant core's text parsing functions - two token based parsers cohexist in Radiant - the primary one (GetToken UnGetToken etc.) is used on the .map parsing etc. - COM_Parse is another parser, used on .def parse for instance - - NOTE: I hope we can totally get rid of this part when we have XML support -*/ - -#define SCRIPLIB_MAJOR "scriptlib" - -typedef qboolean (* PFN_GETTOKEN) (qboolean crossline); -typedef void (* PFN_UNGETTOKEN) (); -// only used to retrieve &token -typedef char* (* PFN_TOKEN) (); -typedef void (* PFN_STARTTOKENPARSING) (char *); -// script line -typedef int (* PFN_SCRIPTLINE) (); -typedef qboolean (* PFN_TOKENAVAILABLE) (); -// COM_Parse -typedef char* (* PFN_COM_PARSE) (char *data); -typedef char* (* PFN_GET_COM_TOKEN) (); -// Hydra: added support for GetTokenExtra() -typedef qboolean (* PFN_GETTOKENEXTRA) (qboolean crossline,char *delimiters,qboolean keepdelimiter); - -struct _QERScripLibTable -{ - float m_fVersion; - int m_nSize; - PFN_GETTOKEN m_pfnGetToken; - PFN_GETTOKENEXTRA m_pfnGetTokenExtra; // Hydra: added support for GetTokenExtra() - PFN_UNGETTOKEN m_pfnUnGetToken; - PFN_TOKEN m_pfnToken; - PFN_STARTTOKENPARSING m_pfnStartTokenParsing; - PFN_SCRIPTLINE m_pfnScriptLine; - PFN_TOKENAVAILABLE m_pfnTokenAvailable; - PFN_COM_PARSE m_pfnCOM_Parse; - PFN_GET_COM_TOKEN m_pfnGet_COM_Token; -}; - -#ifdef USE_SCRIPLIBTABLE_DEFINE -#ifndef __SCRIPLIBTABLENAME -#define __SCRIPLIBTABLENAME g_ScripLibTable -#endif -#define GetToken __SCRIPLIBTABLENAME.m_pfnGetToken -#define Token __SCRIPLIBTABLENAME.m_pfnToken -#define UnGetToken __SCRIPLIBTABLENAME.m_pfnUnGetToken -#define StartTokenParsing __SCRIPLIBTABLENAME.m_pfnStartTokenParsing -#define ScriptLine __SCRIPLIBTABLENAME.m_pfnScriptLine -#define TokenAvailable __SCRIPLIBTABLENAME.m_pfnTokenAvailable -#define COM_Parse __SCRIPLIBTABLENAME.m_pfnCOM_Parse -#define Get_COM_Token __SCRIPLIBTABLENAME.m_pfnGet_COM_Token -#define GetTokenExtra __SCRIPLIBTABLENAME.m_pfnGetTokenExtra // Hydra: added support for GetTokenExtra() -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// all purpose scriplib interface for Q3Radiant plugins (cf. parse.h) +// + +#ifndef __ISCRIPLIB_H_ +#define __ISCRIPLIB_H_ + +/*! \file iscriplib.h + \brief function tables for Radiant core's text parsing functions + two token based parsers cohexist in Radiant + the primary one (GetToken UnGetToken etc.) is used on the .map parsing etc. + COM_Parse is another parser, used on .def parse for instance + + NOTE: I hope we can totally get rid of this part when we have XML support +*/ + +#define SCRIPLIB_MAJOR "scriptlib" + +typedef qboolean (* PFN_GETTOKEN) (qboolean crossline); +typedef void (* PFN_UNGETTOKEN) (); +// only used to retrieve &token +typedef char* (* PFN_TOKEN) (); +typedef void (* PFN_STARTTOKENPARSING) (char *); +// script line +typedef int (* PFN_SCRIPTLINE) (); +typedef qboolean (* PFN_TOKENAVAILABLE) (); +// COM_Parse +typedef char* (* PFN_COM_PARSE) (char *data); +typedef char* (* PFN_GET_COM_TOKEN) (); +// Hydra: added support for GetTokenExtra() +typedef qboolean (* PFN_GETTOKENEXTRA) (qboolean crossline,char *delimiters,qboolean keepdelimiter); + +struct _QERScripLibTable +{ + float m_fVersion; + int m_nSize; + PFN_GETTOKEN m_pfnGetToken; + PFN_GETTOKENEXTRA m_pfnGetTokenExtra; // Hydra: added support for GetTokenExtra() + PFN_UNGETTOKEN m_pfnUnGetToken; + PFN_TOKEN m_pfnToken; + PFN_STARTTOKENPARSING m_pfnStartTokenParsing; + PFN_SCRIPTLINE m_pfnScriptLine; + PFN_TOKENAVAILABLE m_pfnTokenAvailable; + PFN_COM_PARSE m_pfnCOM_Parse; + PFN_GET_COM_TOKEN m_pfnGet_COM_Token; +}; + +#ifdef USE_SCRIPLIBTABLE_DEFINE +#ifndef __SCRIPLIBTABLENAME +#define __SCRIPLIBTABLENAME g_ScripLibTable +#endif +#define GetToken __SCRIPLIBTABLENAME.m_pfnGetToken +#define Token __SCRIPLIBTABLENAME.m_pfnToken +#define UnGetToken __SCRIPLIBTABLENAME.m_pfnUnGetToken +#define StartTokenParsing __SCRIPLIBTABLENAME.m_pfnStartTokenParsing +#define ScriptLine __SCRIPLIBTABLENAME.m_pfnScriptLine +#define TokenAvailable __SCRIPLIBTABLENAME.m_pfnTokenAvailable +#define COM_Parse __SCRIPLIBTABLENAME.m_pfnCOM_Parse +#define Get_COM_Token __SCRIPLIBTABLENAME.m_pfnGet_COM_Token +#define GetTokenExtra __SCRIPLIBTABLENAME.m_pfnGetTokenExtra // Hydra: added support for GetTokenExtra() +#endif + +#endif diff --git a/include/iselectedface.h b/include/iselectedface.h index a01c5283..61bc70d4 100644 --- a/include/iselectedface.h +++ b/include/iselectedface.h @@ -1,88 +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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// Quick interface hack for selected face interface -// this one really needs more work, but I'm in a hurry with TexTool - -#ifndef __ISELECTEDFACE_H_ -#define __ISELECTEDFACE_H_ - -#define SELECTEDFACE_MAJOR "selectedface" -// v2.0 -// support for multiple faces selection (first use in textool v2) -// using the g_ptrSelectedFaces indexes, get the face_t* with GETFACE -// still relies on the _QERFaceData*, unless you cast the face_t* to do your own stuff -// removed PFN_TEXTUREFORNAME, it's in the IShaders API now - -//++timo TODO: this interface needs some cleanup with the new texture / shaders interface - -// number of selected textures -typedef int (WINAPI* PFN_GETSELECTEDFACECOUNT) (); -// retrieve the corresponding brush_t* (we need it when we need to explicitely rebuild stuff) -typedef brush_t* (WINAPI* PFN_GETFACEBRUSH) (int iface); -// retrieve a given face_t* -typedef face_t* (WINAPI* PFN_GETFACE) (int iface); -// winding_t is assumed to have MAX_POINTS_ON_WINDING allocated and waiting -typedef int (WINAPI* PFN_GETFACEINFO) (int iface, _QERFaceData*, winding_t* ); -// tell editor to update the selected face data -typedef int (WINAPI* PFN_SETFACEINFO) (int iface, _QERFaceData*); -// retrieve the texture number to bind to -typedef int (WINAPI* PFN_GETTEXTURENUMBER) (int iface); -// retrieving some texture information -typedef void (WINAPI* PFN_GETTEXTURESIZE) (int iface, int Size[2] ); -// straight func pointer to Select_SetTexture -// last parameter must be casted to an IPluginTexdef -typedef void (WINAPI* PFN_SELECT_SETTEXTURE) (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef); - -// NOTE: some things in there are not really related to the selected face -// having some stuff moved into a textures-dedicated part ? -struct _QERSelectedFaceTable -{ - int m_nSize; - PFN_GETSELECTEDFACECOUNT m_pfnGetSelectedFaceCount; - PFN_GETFACEBRUSH m_pfnGetFaceBrush; - PFN_GETFACE m_pfnGetFace; - PFN_GETFACEINFO m_pfnGetFaceInfo; - PFN_SETFACEINFO m_pfnSetFaceInfo; - PFN_GETTEXTURENUMBER m_pfnGetTextureNumber; - PFN_GETTEXTURESIZE m_pfnGetTextureSize; - PFN_SELECT_SETTEXTURE m_pfnSelect_SetTexture; -}; - -#ifdef USE_SELECTEDFACETABLE_DEFINE - #ifndef __SELECTEDFACETABLENAME - #define __SELECTEDFACETABLENAME g_SelectedFaceTable - #endif - - #define GetSelectedFaceCount __SELECTEDFACETABLENAME.m_pfnGetSelectedFaceCount - #define GetFaceBrush __SELECTEDFACETABLENAME.m_pfnGetFaceBrush - #define GetFace __SELECTEDFACETABLENAME.m_pfnGetFace - #define GetFaceInfo __SELECTEDFACETABLENAME.m_pfnGetFaceInfo - #define SetFaceInfo __SELECTEDFACETABLENAME.m_pfnSetFaceInfo - #define GetTextureNumber __SELECTEDFACETABLENAME.m_pfnGetTextureNumber - #define GetTextureSize __SELECTEDFACETABLENAME.m_pfnGetTextureSize - #define Select_SetTexture __SELECTEDFACETABLENAME.m_pfnSelect_SetTexture -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 + +#ifndef __ISELECTEDFACE_H_ +#define __ISELECTEDFACE_H_ + +#define SELECTEDFACE_MAJOR "selectedface" +// v2.0 +// support for multiple faces selection (first use in textool v2) +// using the g_ptrSelectedFaces indexes, get the face_t* with GETFACE +// still relies on the _QERFaceData*, unless you cast the face_t* to do your own stuff +// removed PFN_TEXTUREFORNAME, it's in the IShaders API now + +//++timo TODO: this interface needs some cleanup with the new texture / shaders interface + +// number of selected textures +typedef int (WINAPI* PFN_GETSELECTEDFACECOUNT) (); +// retrieve the corresponding brush_t* (we need it when we need to explicitely rebuild stuff) +typedef brush_t* (WINAPI* PFN_GETFACEBRUSH) (int iface); +// retrieve a given face_t* +typedef face_t* (WINAPI* PFN_GETFACE) (int iface); +// winding_t is assumed to have MAX_POINTS_ON_WINDING allocated and waiting +typedef int (WINAPI* PFN_GETFACEINFO) (int iface, _QERFaceData*, winding_t* ); +// tell editor to update the selected face data +typedef int (WINAPI* PFN_SETFACEINFO) (int iface, _QERFaceData*); +// retrieve the texture number to bind to +typedef int (WINAPI* PFN_GETTEXTURENUMBER) (int iface); +// retrieving some texture information +typedef void (WINAPI* PFN_GETTEXTURESIZE) (int iface, int Size[2] ); +// straight func pointer to Select_SetTexture +// last parameter must be casted to an IPluginTexdef +typedef void (WINAPI* PFN_SELECT_SETTEXTURE) (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef); + +// NOTE: some things in there are not really related to the selected face +// having some stuff moved into a textures-dedicated part ? +struct _QERSelectedFaceTable +{ + int m_nSize; + PFN_GETSELECTEDFACECOUNT m_pfnGetSelectedFaceCount; + PFN_GETFACEBRUSH m_pfnGetFaceBrush; + PFN_GETFACE m_pfnGetFace; + PFN_GETFACEINFO m_pfnGetFaceInfo; + PFN_SETFACEINFO m_pfnSetFaceInfo; + PFN_GETTEXTURENUMBER m_pfnGetTextureNumber; + PFN_GETTEXTURESIZE m_pfnGetTextureSize; + PFN_SELECT_SETTEXTURE m_pfnSelect_SetTexture; +}; + +#ifdef USE_SELECTEDFACETABLE_DEFINE + #ifndef __SELECTEDFACETABLENAME + #define __SELECTEDFACETABLENAME g_SelectedFaceTable + #endif + + #define GetSelectedFaceCount __SELECTEDFACETABLENAME.m_pfnGetSelectedFaceCount + #define GetFaceBrush __SELECTEDFACETABLENAME.m_pfnGetFaceBrush + #define GetFace __SELECTEDFACETABLENAME.m_pfnGetFace + #define GetFaceInfo __SELECTEDFACETABLENAME.m_pfnGetFaceInfo + #define SetFaceInfo __SELECTEDFACETABLENAME.m_pfnSetFaceInfo + #define GetTextureNumber __SELECTEDFACETABLENAME.m_pfnGetTextureNumber + #define GetTextureSize __SELECTEDFACETABLENAME.m_pfnGetTextureSize + #define Select_SetTexture __SELECTEDFACETABLENAME.m_pfnSelect_SetTexture +#endif + +#endif diff --git a/include/ishaders.h b/include/ishaders.h index 17cafc36..e50233ed 100644 --- a/include/ishaders.h +++ b/include/ishaders.h @@ -1,284 +1,284 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 set of functions to manipulate textures in Radiant -// - -#ifndef __ISHADERS_H_ -#define __ISHADERS_H_ - -#define SHADERS_MAJOR "shaders" -// define a GUID for this interface so plugins can access and reference it -// {D42F798A-DF57-11d3-A3EE-0004AC96D4C3} -static const GUID QERShadersTable_GUID = -{ 0xd42f798a, 0xdf57, 0x11d3, { 0xa3, 0xee, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; - -// NOTES ABOUT SYNTAX: -// if a function starts by 'Try' it means that if the requested thing could not be found / loaded it will return nothing / NULL -// otherwise a default object will be created -// the _QERShadersTable is also used by shader code inside Radiant. but for speed and "keep it simple" consideration you -// can get the static equivalent of the func pointers by adding 'QERApp_' (access to _QERShadersTable is better thought .. -// see the note to move all the shader language out of Radiant below) - -/*! -\todo FIXME TTimo -fix the reference count strategy -- define the policy. It seems the initial policy of doing an inc ref when you create the shader is not good -(it doesn't work, and it's not being used right) -so, when you request an IShader and store it, incref it yourself -as a debugging safe check: push the created increfed objects into a list, and scan them at next idle loop -to make sure they have been decref'ed ? (sounds easy, may not be that much). -*/ - -class IShader -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // get/set the qtexture_t* Radiant uses to represent this shader object - virtual qtexture_t* getTexture() const = 0; - virtual void setTexture(qtexture_t *pTex) = 0; - // get shader name - virtual const char* getName() const = 0; - // is this shader in use? - // NOTE: this flag can mean this shader has been in use at least once since the last rescan of in-use stuff - // (rescan of in-use happens in several cases, user command or during a texture directory load) - // NOTE: this is used to draw the green outline in the texture window - // NOTE: when does Radiant set the InUse flag? Whenever Select_SetTexture is called (well that doesn't necessarily means the texture actually gets in use, but that's close enough) - virtual bool IsInUse() const = 0; - virtual void SetInUse(bool) = 0; - // is this shader displayed in the texture browser? - // NOTE: if IsInUse() == true, the shader will always be displayed in the texture window and this flag ingored - virtual bool IsDisplayed() const = 0; - virtual void SetDisplayed(bool) = 0; - // get the editor flags (QER_NOCARVE QER_TRANS) - virtual int getFlags() = 0; - // get the transparency value - virtual float getTrans() = 0; - // test if it's a true shader, or a default shader created to wrap around a texture - virtual bool IsDefault() = 0; - // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) - virtual bool IsColor() = 0; - // get the related color then! - virtual void getColor(vec3_t v) = 0; - // get the alphaFunc - virtual void getAlphaFunc(int *func, float *ref) = 0; - // get the cull type - virtual int getCull() = 0; - // get shader file name (ie the file where this one is defined) - virtual const char* getShaderFileName() const = 0; -}; - -// NOTE: how to move all the shader language out of Radiant in a plugin? -// -> change this _QERShadersTable into an IShadersManager -// -> let the plugin create an instance of IShadersManager -// -> make sure Radiant uses this IShadersManager to load / query the shaders - -// NOTE: shader and texture names used must be full path, ie. most often with "textures/" prefix -// (since shaders are defined in .shader files with textures/) - -// free all shaders -// free the shaders, will not free the qtexture_t* -typedef void (WINAPI* PFN_FREESHADERS) (); -// reload all the shaders -// this will free everything (shaders and their textures), then reload all in use stuff -typedef void (WINAPI* PFN_RELOADSHADERS) (); -// load all shaders in a given directory -// this will scan the list of in-memory shaders, and load the related qtexture_t if needed -typedef int (WINAPI* PFN_LOADSHADERSFROMDIR)(const char* path); -// load a shader file (ie a set of shaders) -// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them -// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders! -typedef void (WINAPI* PFN_LOADSHADERFILE) (const char* filename); -// tell if a given shader exists in our shader table -// NOTE: this doesn't tell wether it's corresponding qtexture is loaded -typedef int (WINAPI* PFN_HASSHADER) (const char* name); -// return the shader for a given name -// if the qtexture is not already in memory, will try loading it -// if the qtexture could not be found, will use default -// will return NULL on shader not found -typedef IShader* (WINAPI* PFN_TRYSHADERFORNAME) (const char* name); -// return the shader for a given name -// if the qtexture is not already in memory, will try loading it -// will create a default shader if not found (will use a default texture) -typedef IShader* (WINAPI* PFN_SHADERFORNAME) (const char* name); -// query / load a texture -// will not try loading a shader, will look for the actual image file .. -// returns NULL on file not found -// NOTE: strategy for file lookup: -// paths must be relative, ie. textures/me/myfile -// if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first -// if not found or no extension, will try loading after adding .tga and .jpg (in this order) -typedef qtexture_t* (WINAPI* PFN_TRYTEXTUREFORNAME) (const char* filename); -// query / load a texture -// will not try loading a shader, will look for the actual image file .. -// on file not found will use the "texture not found" -typedef qtexture_t* (WINAPI* PFN_TEXTUREFORNAME) (const char* filename); -// get the number of active shaders -// these are the shaders currently loaded, that have an associated qtexture_t* -typedef int (WINAPI* PFN_GETACTIVESHADERCOUNT) (); -// for stuff that needs to be represented by a plain texture -// the shader will get a "color" name, use GetColor to get the actual color -typedef IShader* (WINAPI* PFN_COLORSHADERFORNAME) (const char* name); -// reload a shaderfile - update shaders and their display properties/qtexture_t if needed -// will not reload the texture files -// will switch to "show in use" atfer use -// filename must be reletive path of the shader, ex. scripts/gothic_wall.shader -typedef void (WINAPI* PFN_RELOADSHADERFILE)(const char* filename); -// retrieve a shader if exists, without loading the textures for it etc. -// use this function if you want special info on a shader -typedef IShader* (WINAPI* PFN_SHADERFORNAMENOLOAD) (const char* name); -// force the "in use" flag on all active shaders -typedef void (WINAPI* PFN_ACTIVESHADERSSETINUSE) (bool b); -// sort the shaders in alphabetical order, we use the order in the texture inspector -typedef void (WINAPI* PFN_SORTACTIVESHADERS) (); -// check if there exists an active shader with the given texture name (loaded or not, doesn't matter) -// (used to detect the textures we need to create a default shader for .. while scanning a directory) -typedef IShader* (WINAPI* PFN_ACTIVESHADERFORTEXTURENAME) (char *); -// create a shader to wrap around a texture name, we use this when loading a texture directory and some textures -// are not present as shaders -typedef IShader* (WINAPI* PFN_CREATESHADERFORTEXTURENAME) (const char* name); -// switch the IsDisplayed flag on all the active shaders -typedef void (WINAPI* PFN_ACTIVESHADERSSETDISPLAYED) (bool b); -// retrieve an active shader based on index -typedef IShader* (WINAPI* PFN_ACTIVESHADERFORINDEX) (int i); -// will cleanup a texture name and force it to the right format -// the debug version is painfully slow, but will detect more problems -// the idea being to avoid loading the same file several time because of uppercase/lowercase etc. -typedef const char* (WINAPI* PFN_CLEANTEXTURENAME) (const char* name, bool bAddTexture); - -struct _QERShadersTable -{ - int m_nSize; - PFN_FREESHADERS m_pfnFreeShaders; - PFN_RELOADSHADERS m_pfnReloadShaders; - PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir; - PFN_LOADSHADERFILE m_pfnLoadShaderFile; - PFN_RELOADSHADERFILE m_pfnReloadShaderFile; - PFN_HASSHADER m_pfnHasShader; - PFN_TRYSHADERFORNAME m_pfnTry_Shader_ForName; - PFN_SHADERFORNAME m_pfnShader_ForName; - PFN_TRYTEXTUREFORNAME m_pfnTry_Texture_ForName; - PFN_TEXTUREFORNAME m_pfnTexture_ForName; - PFN_GETACTIVESHADERCOUNT m_pfnGetActiveShaderCount; - PFN_COLORSHADERFORNAME m_pfnColorShader_ForName; - PFN_SHADERFORNAMENOLOAD m_pfnShader_ForName_NoLoad; - PFN_ACTIVESHADERSSETINUSE m_pfnActiveShaders_SetInUse; - PFN_SORTACTIVESHADERS m_pfnSortActiveShaders; - PFN_ACTIVESHADERFORTEXTURENAME m_pfnActiveShader_ForTextureName; - PFN_CREATESHADERFORTEXTURENAME m_pfnCreateShader_ForTextureName; - PFN_ACTIVESHADERSSETDISPLAYED m_pfnActiveShaders_SetDisplayed; - PFN_ACTIVESHADERFORINDEX m_pfnActiveShader_ForIndex; - PFN_CLEANTEXTURENAME m_pfnCleanTextureName; -}; - -/*! -\todo FIXME fix the QERApp_ prototyping on shaders module -make it homogeneous with other modules, should be straight calls -*/ - -#ifdef USE_SHADERSTABLE_DEFINE - #ifndef __SHADERSTABLENAME - #define __SHADERSTABLENAME g_ShadersTable - #endif -#define QERApp_Shader_ForName __SHADERSTABLENAME.m_pfnShader_ForName -#define QERApp_Texture_ForName2 __SHADERSTABLENAME.m_pfnTexture_ForName -#define QERApp_FreeShaders __SHADERSTABLENAME.m_pfnFreeShaders -#define QERApp_ReloadShaders __SHADERSTABLENAME.m_pfnReloadShaders -#define QERApp_SortActiveShaders __SHADERSTABLENAME.m_pfnSortActiveShaders -#define QERApp_ReloadShaderFile __SHADERSTABLENAME.m_pfnReloadShaderFile -#define QERApp_LoadShaderFile __SHADERSTABLENAME.m_pfnLoadShaderFile -#define QERApp_HasShader __SHADERSTABLENAME.m_pfnHasShader -#define QERApp_Try_Shader_ForName __SHADERSTABLENAME.m_pfnTry_Shader_ForName -#define QERApp_Try_Texture_ForName __SHADERSTABLENAME.m_pfnTry_Texture_ForName -#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName -#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad -#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir -#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir -#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName -#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount -#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed -#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex -#define QERApp_ActiveShaders_SetInUse __SHADERSTABLENAME.m_pfnActiveShaders_SetInUse -#define QERApp_ActiveShader_ForTextureName __SHADERSTABLENAME.m_pfnActiveShader_ForTextureName -#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex -#define QERApp_CleanTextureName __SHADERSTABLENAME.m_pfnCleanTextureName -#endif - -#define APPSHADERS_MAJOR "appshaders" -// FIXME: remove -static const GUID QERAppShadersTable_GUID = -{ 0xec3008a8, 0xbd0b, 0x11d4, { 0x82, 0x51, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20 } }; - -// g_qeglobals.d_qtextures is used internally by the editor for actual camera drawing -typedef qtexture_t** (WINAPI* PFN_QTEXTURES)(); -// g_qeglobals.d_qtexmap is a map for fast access -typedef GHashTable* (WINAPI* PFN_QTEXMAP)(); -// d_texturewin -//++timo NOTE: this same function is also in isurface.h table, we would eventually have to merge some stuff -typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN)(); -// Texture_SetTexture -//++timo NOTE: this one may have to be reorganized too .. putting it here is a bit clumsy -// NOTE: the C++ function used internally has a lot of default values -typedef void (WINAPI* PFN_TEXTURESETTEXTURE)(texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef); -// Texture_ShowInuse -typedef void (WINAPI* PFN_TEXTURESHOWINUSE)(); -// BuildShaderList -typedef void (* PFN_BUILDSHADERLIST)(); -// PreloadShaders -typedef void (* PFN_PRELOADSHADERS)(); - -// a table that Radiant makes available to the shader module in return -struct _QERAppShadersTable -{ - int m_nSize; - PFN_QTEXTURES m_pfnQTextures; - PFN_QTEXMAP m_pfnQTexmap; - PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; - PFN_TEXTURESETTEXTURE m_pfnTexture_SetTexture; - PFN_TEXTURESHOWINUSE m_pfnTexture_ShowInuse; - PFN_BUILDSHADERLIST m_pfnBuildShaderList; - PFN_PRELOADSHADERS m_pfnPreloadShaders; -}; - -#ifdef USE_APPSHADERSTABLE_DEFINE - #ifndef __APPSHADERTABLENAME - #define __APPSHADERTABLENAME g_AppShadersTable - #endif -#define Texture_ShowInuse __APPSHADERTABLENAME.m_pfnTexture_ShowInuse -#endif - -/*! -NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX: -SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this -SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it -this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in -*/ -#define SHADER_NOT_FOUND "textures/radiant/notex" -#define SHADER_NOTEX "textures/radiant/shadernotex" ///< Q3 tech specific - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 set of functions to manipulate textures in Radiant +// + +#ifndef __ISHADERS_H_ +#define __ISHADERS_H_ + +#define SHADERS_MAJOR "shaders" +// define a GUID for this interface so plugins can access and reference it +// {D42F798A-DF57-11d3-A3EE-0004AC96D4C3} +static const GUID QERShadersTable_GUID = +{ 0xd42f798a, 0xdf57, 0x11d3, { 0xa3, 0xee, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// NOTES ABOUT SYNTAX: +// if a function starts by 'Try' it means that if the requested thing could not be found / loaded it will return nothing / NULL +// otherwise a default object will be created +// the _QERShadersTable is also used by shader code inside Radiant. but for speed and "keep it simple" consideration you +// can get the static equivalent of the func pointers by adding 'QERApp_' (access to _QERShadersTable is better thought .. +// see the note to move all the shader language out of Radiant below) + +/*! +\todo FIXME TTimo +fix the reference count strategy +- define the policy. It seems the initial policy of doing an inc ref when you create the shader is not good +(it doesn't work, and it's not being used right) +so, when you request an IShader and store it, incref it yourself +as a debugging safe check: push the created increfed objects into a list, and scan them at next idle loop +to make sure they have been decref'ed ? (sounds easy, may not be that much). +*/ + +class IShader +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // get/set the qtexture_t* Radiant uses to represent this shader object + virtual qtexture_t* getTexture() const = 0; + virtual void setTexture(qtexture_t *pTex) = 0; + // get shader name + virtual const char* getName() const = 0; + // is this shader in use? + // NOTE: this flag can mean this shader has been in use at least once since the last rescan of in-use stuff + // (rescan of in-use happens in several cases, user command or during a texture directory load) + // NOTE: this is used to draw the green outline in the texture window + // NOTE: when does Radiant set the InUse flag? Whenever Select_SetTexture is called (well that doesn't necessarily means the texture actually gets in use, but that's close enough) + virtual bool IsInUse() const = 0; + virtual void SetInUse(bool) = 0; + // is this shader displayed in the texture browser? + // NOTE: if IsInUse() == true, the shader will always be displayed in the texture window and this flag ingored + virtual bool IsDisplayed() const = 0; + virtual void SetDisplayed(bool) = 0; + // get the editor flags (QER_NOCARVE QER_TRANS) + virtual int getFlags() = 0; + // get the transparency value + virtual float getTrans() = 0; + // test if it's a true shader, or a default shader created to wrap around a texture + virtual bool IsDefault() = 0; + // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) + virtual bool IsColor() = 0; + // get the related color then! + virtual void getColor(vec3_t v) = 0; + // get the alphaFunc + virtual void getAlphaFunc(int *func, float *ref) = 0; + // get the cull type + virtual int getCull() = 0; + // get shader file name (ie the file where this one is defined) + virtual const char* getShaderFileName() const = 0; +}; + +// NOTE: how to move all the shader language out of Radiant in a plugin? +// -> change this _QERShadersTable into an IShadersManager +// -> let the plugin create an instance of IShadersManager +// -> make sure Radiant uses this IShadersManager to load / query the shaders + +// NOTE: shader and texture names used must be full path, ie. most often with "textures/" prefix +// (since shaders are defined in .shader files with textures/) + +// free all shaders +// free the shaders, will not free the qtexture_t* +typedef void (WINAPI* PFN_FREESHADERS) (); +// reload all the shaders +// this will free everything (shaders and their textures), then reload all in use stuff +typedef void (WINAPI* PFN_RELOADSHADERS) (); +// load all shaders in a given directory +// this will scan the list of in-memory shaders, and load the related qtexture_t if needed +typedef int (WINAPI* PFN_LOADSHADERSFROMDIR)(const char* path); +// load a shader file (ie a set of shaders) +// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them +// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders! +typedef void (WINAPI* PFN_LOADSHADERFILE) (const char* filename); +// tell if a given shader exists in our shader table +// NOTE: this doesn't tell wether it's corresponding qtexture is loaded +typedef int (WINAPI* PFN_HASSHADER) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// if the qtexture could not be found, will use default +// will return NULL on shader not found +typedef IShader* (WINAPI* PFN_TRYSHADERFORNAME) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// will create a default shader if not found (will use a default texture) +typedef IShader* (WINAPI* PFN_SHADERFORNAME) (const char* name); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// returns NULL on file not found +// NOTE: strategy for file lookup: +// paths must be relative, ie. textures/me/myfile +// if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first +// if not found or no extension, will try loading after adding .tga and .jpg (in this order) +typedef qtexture_t* (WINAPI* PFN_TRYTEXTUREFORNAME) (const char* filename); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// on file not found will use the "texture not found" +typedef qtexture_t* (WINAPI* PFN_TEXTUREFORNAME) (const char* filename); +// get the number of active shaders +// these are the shaders currently loaded, that have an associated qtexture_t* +typedef int (WINAPI* PFN_GETACTIVESHADERCOUNT) (); +// for stuff that needs to be represented by a plain texture +// the shader will get a "color" name, use GetColor to get the actual color +typedef IShader* (WINAPI* PFN_COLORSHADERFORNAME) (const char* name); +// reload a shaderfile - update shaders and their display properties/qtexture_t if needed +// will not reload the texture files +// will switch to "show in use" atfer use +// filename must be reletive path of the shader, ex. scripts/gothic_wall.shader +typedef void (WINAPI* PFN_RELOADSHADERFILE)(const char* filename); +// retrieve a shader if exists, without loading the textures for it etc. +// use this function if you want special info on a shader +typedef IShader* (WINAPI* PFN_SHADERFORNAMENOLOAD) (const char* name); +// force the "in use" flag on all active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETINUSE) (bool b); +// sort the shaders in alphabetical order, we use the order in the texture inspector +typedef void (WINAPI* PFN_SORTACTIVESHADERS) (); +// check if there exists an active shader with the given texture name (loaded or not, doesn't matter) +// (used to detect the textures we need to create a default shader for .. while scanning a directory) +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORTEXTURENAME) (char *); +// create a shader to wrap around a texture name, we use this when loading a texture directory and some textures +// are not present as shaders +typedef IShader* (WINAPI* PFN_CREATESHADERFORTEXTURENAME) (const char* name); +// switch the IsDisplayed flag on all the active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETDISPLAYED) (bool b); +// retrieve an active shader based on index +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORINDEX) (int i); +// will cleanup a texture name and force it to the right format +// the debug version is painfully slow, but will detect more problems +// the idea being to avoid loading the same file several time because of uppercase/lowercase etc. +typedef const char* (WINAPI* PFN_CLEANTEXTURENAME) (const char* name, bool bAddTexture); + +struct _QERShadersTable +{ + int m_nSize; + PFN_FREESHADERS m_pfnFreeShaders; + PFN_RELOADSHADERS m_pfnReloadShaders; + PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir; + PFN_LOADSHADERFILE m_pfnLoadShaderFile; + PFN_RELOADSHADERFILE m_pfnReloadShaderFile; + PFN_HASSHADER m_pfnHasShader; + PFN_TRYSHADERFORNAME m_pfnTry_Shader_ForName; + PFN_SHADERFORNAME m_pfnShader_ForName; + PFN_TRYTEXTUREFORNAME m_pfnTry_Texture_ForName; + PFN_TEXTUREFORNAME m_pfnTexture_ForName; + PFN_GETACTIVESHADERCOUNT m_pfnGetActiveShaderCount; + PFN_COLORSHADERFORNAME m_pfnColorShader_ForName; + PFN_SHADERFORNAMENOLOAD m_pfnShader_ForName_NoLoad; + PFN_ACTIVESHADERSSETINUSE m_pfnActiveShaders_SetInUse; + PFN_SORTACTIVESHADERS m_pfnSortActiveShaders; + PFN_ACTIVESHADERFORTEXTURENAME m_pfnActiveShader_ForTextureName; + PFN_CREATESHADERFORTEXTURENAME m_pfnCreateShader_ForTextureName; + PFN_ACTIVESHADERSSETDISPLAYED m_pfnActiveShaders_SetDisplayed; + PFN_ACTIVESHADERFORINDEX m_pfnActiveShader_ForIndex; + PFN_CLEANTEXTURENAME m_pfnCleanTextureName; +}; + +/*! +\todo FIXME fix the QERApp_ prototyping on shaders module +make it homogeneous with other modules, should be straight calls +*/ + +#ifdef USE_SHADERSTABLE_DEFINE + #ifndef __SHADERSTABLENAME + #define __SHADERSTABLENAME g_ShadersTable + #endif +#define QERApp_Shader_ForName __SHADERSTABLENAME.m_pfnShader_ForName +#define QERApp_Texture_ForName2 __SHADERSTABLENAME.m_pfnTexture_ForName +#define QERApp_FreeShaders __SHADERSTABLENAME.m_pfnFreeShaders +#define QERApp_ReloadShaders __SHADERSTABLENAME.m_pfnReloadShaders +#define QERApp_SortActiveShaders __SHADERSTABLENAME.m_pfnSortActiveShaders +#define QERApp_ReloadShaderFile __SHADERSTABLENAME.m_pfnReloadShaderFile +#define QERApp_LoadShaderFile __SHADERSTABLENAME.m_pfnLoadShaderFile +#define QERApp_HasShader __SHADERSTABLENAME.m_pfnHasShader +#define QERApp_Try_Shader_ForName __SHADERSTABLENAME.m_pfnTry_Shader_ForName +#define QERApp_Try_Texture_ForName __SHADERSTABLENAME.m_pfnTry_Texture_ForName +#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName +#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName +#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount +#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_ActiveShaders_SetInUse __SHADERSTABLENAME.m_pfnActiveShaders_SetInUse +#define QERApp_ActiveShader_ForTextureName __SHADERSTABLENAME.m_pfnActiveShader_ForTextureName +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_CleanTextureName __SHADERSTABLENAME.m_pfnCleanTextureName +#endif + +#define APPSHADERS_MAJOR "appshaders" +// FIXME: remove +static const GUID QERAppShadersTable_GUID = +{ 0xec3008a8, 0xbd0b, 0x11d4, { 0x82, 0x51, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20 } }; + +// g_qeglobals.d_qtextures is used internally by the editor for actual camera drawing +typedef qtexture_t** (WINAPI* PFN_QTEXTURES)(); +// g_qeglobals.d_qtexmap is a map for fast access +typedef GHashTable* (WINAPI* PFN_QTEXMAP)(); +// d_texturewin +//++timo NOTE: this same function is also in isurface.h table, we would eventually have to merge some stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN)(); +// Texture_SetTexture +//++timo NOTE: this one may have to be reorganized too .. putting it here is a bit clumsy +// NOTE: the C++ function used internally has a lot of default values +typedef void (WINAPI* PFN_TEXTURESETTEXTURE)(texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef); +// Texture_ShowInuse +typedef void (WINAPI* PFN_TEXTURESHOWINUSE)(); +// BuildShaderList +typedef void (* PFN_BUILDSHADERLIST)(); +// PreloadShaders +typedef void (* PFN_PRELOADSHADERS)(); + +// a table that Radiant makes available to the shader module in return +struct _QERAppShadersTable +{ + int m_nSize; + PFN_QTEXTURES m_pfnQTextures; + PFN_QTEXMAP m_pfnQTexmap; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_TEXTURESETTEXTURE m_pfnTexture_SetTexture; + PFN_TEXTURESHOWINUSE m_pfnTexture_ShowInuse; + PFN_BUILDSHADERLIST m_pfnBuildShaderList; + PFN_PRELOADSHADERS m_pfnPreloadShaders; +}; + +#ifdef USE_APPSHADERSTABLE_DEFINE + #ifndef __APPSHADERTABLENAME + #define __APPSHADERTABLENAME g_AppShadersTable + #endif +#define Texture_ShowInuse __APPSHADERTABLENAME.m_pfnTexture_ShowInuse +#endif + +/*! +NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX: +SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this +SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it +this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in +*/ +#define SHADER_NOT_FOUND "textures/radiant/notex" +#define SHADER_NOTEX "textures/radiant/shadernotex" ///< Q3 tech specific + +#endif diff --git a/include/ishadersmanager.h b/include/ishadersmanager.h index a9bf0f03..06ac9d32 100644 --- a/include/ishadersmanager.h +++ b/include/ishadersmanager.h @@ -1,102 +1,102 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _ISHADERSMANAGER_H_ -#define _ISHADERSMANAGER_H_ - -class IShadersManager -{ - public: - IShadersManager (); - virtual ~IShadersManager (); - - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - - // free all shaders - // free the shaders, will not free the qtexture_t* - virtual void FreeShaders () = 0; - - // reload all the shaders - // this will free everything (shaders and their textures), then reload all in use stuff - virtual void ReloadShaders () = 0; - - // load all shaders in a given directory - // this will scan the list of in-memory shaders, and load the related qtexture_t if needed - virtual void LoadShadersFromDir (const char* path) = 0; - - // load a shader file (ie a set of shaders) - // after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses - // to represent them if a shader with the same name exists, new one will not be loaded - // don't use this to refresh the shaders! - virtual void LoadShaderFile (const char* filename) = 0; - - // tell if a given shader exists in our shader table - // NOTE: this doesn't tell wether it's corresponding qtexture is loaded - virtual int HasShader (const char* name) = 0; - - // return the shader for a given name - // if the qtexture is not already in memory, will try loading it - // if the qtexture could not be found, will use default - // will return NULL on shader not found - virtual IShader* Try_Shader_ForName (const char* name) = 0; - - // return the shader for a given name - // if the qtexture is not already in memory, will try loading it - // will create a default shader if not found (will use a default texture) - virtual IShader* Shader_ForName (const char* name) = 0; - - // query / load a texture - // will not try loading a shader, will look for the actual image file .. - // returns NULL on file not found - // NOTE: strategy for file lookup: - // paths must be relative, ie. textures/me/myfile - // if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first - // if not found or no extension, will try loading after adding .tga and .jpg (in this order) - virtual qtexture_t* Try_Texture_ForName (const char* filename) = 0; - - // query / load a texture - // will not try loading a shader, will look for the actual image file .. - // on file not found will use the "texture not found" - virtual qtexture_t* Texture_ForName (const char* filename) = 0; - - // get the number of active shaders - // these are the shaders currently loaded, that have an associated qtexture_t* - virtual int GetActiveShaderCount () = 0; - - // for stuff that needs to be represented by a plain texture - // the shader will get a "color" name, use GetColor to get the actual color - virtual IShader* ColorShader_ForName (const char* name) = 0; - - // reload a shaderfile - update shaders and their display properties/qtexture_t if needed - // will not reload the texture files - // will switch to "show in use" atfer use - // filename must be reletive path of the shader, ex. scripts/gothic_wall.shader - virtual void ReloadShaderFile (const char* filename) = 0; - - // retrieve a shader if exists, without loading the textures for it etc. - // use this function if you want special info on a shader - virtual IShader* Shader_ForName_NoLoad (const char* name) = 0; -}; - -#endif // _ISHADERSMANAGER_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _ISHADERSMANAGER_H_ +#define _ISHADERSMANAGER_H_ + +class IShadersManager +{ + public: + IShadersManager (); + virtual ~IShadersManager (); + + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + + // free all shaders + // free the shaders, will not free the qtexture_t* + virtual void FreeShaders () = 0; + + // reload all the shaders + // this will free everything (shaders and their textures), then reload all in use stuff + virtual void ReloadShaders () = 0; + + // load all shaders in a given directory + // this will scan the list of in-memory shaders, and load the related qtexture_t if needed + virtual void LoadShadersFromDir (const char* path) = 0; + + // load a shader file (ie a set of shaders) + // after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses + // to represent them if a shader with the same name exists, new one will not be loaded + // don't use this to refresh the shaders! + virtual void LoadShaderFile (const char* filename) = 0; + + // tell if a given shader exists in our shader table + // NOTE: this doesn't tell wether it's corresponding qtexture is loaded + virtual int HasShader (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // if the qtexture could not be found, will use default + // will return NULL on shader not found + virtual IShader* Try_Shader_ForName (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // will create a default shader if not found (will use a default texture) + virtual IShader* Shader_ForName (const char* name) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // returns NULL on file not found + // NOTE: strategy for file lookup: + // paths must be relative, ie. textures/me/myfile + // if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first + // if not found or no extension, will try loading after adding .tga and .jpg (in this order) + virtual qtexture_t* Try_Texture_ForName (const char* filename) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // on file not found will use the "texture not found" + virtual qtexture_t* Texture_ForName (const char* filename) = 0; + + // get the number of active shaders + // these are the shaders currently loaded, that have an associated qtexture_t* + virtual int GetActiveShaderCount () = 0; + + // for stuff that needs to be represented by a plain texture + // the shader will get a "color" name, use GetColor to get the actual color + virtual IShader* ColorShader_ForName (const char* name) = 0; + + // reload a shaderfile - update shaders and their display properties/qtexture_t if needed + // will not reload the texture files + // will switch to "show in use" atfer use + // filename must be reletive path of the shader, ex. scripts/gothic_wall.shader + virtual void ReloadShaderFile (const char* filename) = 0; + + // retrieve a shader if exists, without loading the textures for it etc. + // use this function if you want special info on a shader + virtual IShader* Shader_ForName_NoLoad (const char* name) = 0; +}; + +#endif // _ISHADERSMANAGER_H_ diff --git a/include/isurfaceplugin.h b/include/isurfaceplugin.h index 6783bb2c..d7be03fd 100644 --- a/include/isurfaceplugin.h +++ b/include/isurfaceplugin.h @@ -1,158 +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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// -// - -#ifndef __ISURFACEPLUGIN_H_ -#define __ISURFACEPLUGIN_H_ - -typedef struct _GtkWidget GtkWidget; -typedef struct _GtkWindow GtkWindow; - -#define SURFACEDIALOG_MAJOR "surfdialog" - -// there's a void* in each qtexture_t, must be casted to a IPluginTexdef* -// there's a void* in each face_t, must be casted to a IPluginTexdef* -// NOTE: IPluginTexdef stores a pointer to the qtexture_t or face_t it's stored in -// members of IPluginTexdef often access the qtexture_t or face_t they are connected to - -// Write texdef needs a function pointer, because Radiant either writes into a FILE or a CMemFile -typedef void (* PFN_QERAPP_MAPPRINTF) ( char *text, ... ); - -class IPluginTexdef -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; -}; - - - -// Nurail: For SI module -class texdef_to_face_t -{ -public: - texdef_to_face_t* next; - brush_t *brush; // Brush faces belong to (for Undo) - face_t *face; // Face of Texdef - texdef_t texdef; // Working texdef - texdef_t orig_texdef; // Original, for baselining changes -}; - - -typedef void (* PFN_QERPLUG_DOSURFACE) (); -typedef void (* PFN_QERPLUG_TOGGLESURFACE) (); -typedef void (* PFN_QERPLUG_UPDATESURFACEDIALOG) (); -typedef void (* PFN_QERPLUG_SURFACEDLGFITALL) (); -typedef GtkWidget* (* PFN_GET_SI_MODULE_WIDGET) (); - -struct _QERPlugSurfaceTable -{ - int m_nSize; - PFN_QERPLUG_TOGGLESURFACE m_pfnToggleSurface; - PFN_QERPLUG_DOSURFACE m_pfnDoSurface; - PFN_QERPLUG_UPDATESURFACEDIALOG m_pfnUpdateSurfaceDialog; - PFN_QERPLUG_SURFACEDLGFITALL m_pfnSurfaceDlgFitAll; - PFN_GET_SI_MODULE_WIDGET m_pfnGet_SI_Module_Widget; -}; - -// this one is used by the plugin to access some Radiant stuff - -#define APPSURFACEDIALOG_MAJOR "appsurfdialog" - -// {42BAE4C0-9787-11d3-8EF3-0000E8E8657B} -static const GUID QERAppSurfaceTable_GUID = -{ 0x42bae4c0, 0x9787, 0x11d3, { 0x8e, 0xf3, 0x0, 0x0, 0xe8, 0xe8, 0x65, 0x7b } }; - -typedef bool (* PFN_PATCHESSELECTED) (); -// retrieve g_qeglobals.texturewin_t -//++timo FIXME: this should move in a dedicated table for all g_qeglobals stuff -typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN) (); -// look for the first selected patch mesh -//++timo FIXME: this is a convenient func since there's no way to scan patches ( yet ) -typedef patchMesh_t* (* PFN_GETSELECTEDPATCH) (); -//++timo FIXME: this one in particular is a hack -typedef void (* PFN_GETTWOSELECTEDPATCH) (patchMesh_t **p1, patchMesh_t **p2); - - -// leo FIXME: hacks uglier than the ones above -typedef void (* PFN_TEXMATTOFAKETEXCOORDS) (vec_t texMat[2][3], float shift[2], float *rot, float scale[2]); -typedef void (* PFN_CONVERTTEXMATWITHQTEXTURE) (brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2); -typedef void (* PFN_FAKETEXCOORDSTOTEXMAT) (float shift[2], float rot, float scale[2], vec_t texMat[2][3]); -typedef void (* PFN_PATCH_RESETTEXTURING) (float fx, float fy); -typedef void (* PFN_PATCH_FITTEXTURING) (); -typedef void (* PFN_PATCH_NATURALIZESELECTED) (bool bCap); -typedef const char* (* PFN_PATCH_GETTEXTURENAME) (); -typedef qboolean (* PFN_QE_SINGLEBRUSH) (bool bQuiet); -typedef qboolean (* PFN_ISBRUSHPRIMITMODE) (); -typedef void (* PFN_SELECT_FITTEXTURE)(int nHeight, int nWidth); -typedef void (*PFN_COMPUTEAXISBASE)(vec3_t normal,vec3_t texS,vec3_t texT ); -typedef void (*PFN_BPMATMUL)(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); -typedef void (*PFN_EMITBRUSHPRIMITTEXCOORDS)(face_t * f, winding_t * w); -typedef texdef_t* (*PFN_QEGLOBALSSAVEDINFO_SIINC) (); -typedef float (* PFN_QEGLOBALSGETGRIDSIZE) (); -typedef void (* PFN_FACELIST_FITTEXTURE) (texdef_to_face_t* texdef_face_list, int nHeight, int nWidth); -typedef GtkWindow* (* PFN_GETMAINWINDOW)(); -typedef void (* PFN_SETWINPOS_FROM_PREFS) (GtkWidget *win); -typedef int (* PFN_GETSELECTEDFACECOUNT_BRUSH) (); -typedef void (* PFN_GETSELFACESTEXDEF) (texdef_to_face_t *); -typedef void (* PFN_SETTEXDEF_FACELIST) (texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale); -typedef void (* PFN_SETACTIVEINRADIANT) (); - - -struct _QERAppSurfaceTable -{ - int m_nSize; - PFN_PATCHESSELECTED m_pfnOnlyPatchesSelected; - PFN_PATCHESSELECTED m_pfnAnyPatchesSelected; - PFN_GETSELECTEDPATCH m_pfnGetSelectedPatch; - PFN_GETTWOSELECTEDPATCH m_pfnGetTwoSelectedPatch; - PFN_TEXMATTOFAKETEXCOORDS m_pfnTexMatToFakeTexCoords; - PFN_CONVERTTEXMATWITHQTEXTURE m_pfnConvertTexMatWithQTexture; - PFN_FAKETEXCOORDSTOTEXMAT m_pfnFakeTexCoordsToTexMat; - PFN_PATCH_RESETTEXTURING m_pfnPatch_ResetTexturing; - PFN_PATCH_FITTEXTURING m_pfnPatch_FitTexturing; - PFN_PATCH_NATURALIZESELECTED m_pfnPatch_NaturalizeSelected; - PFN_PATCH_GETTEXTURENAME m_pfnPatch_GetTextureName; - PFN_QE_SINGLEBRUSH m_pfnQE_SingleBrush; - PFN_ISBRUSHPRIMITMODE m_pfnIsBrushPrimitMode; - PFN_COMPUTEAXISBASE m_pfnComputeAxisBase; - PFN_BPMATMUL m_pfnBPMatMul; - PFN_EMITBRUSHPRIMITTEXCOORDS m_pfnEmitBrushPrimitTextureCoordinates; - PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; - PFN_SELECT_FITTEXTURE m_pfnSelect_FitTexture; - PFN_QEGLOBALSSAVEDINFO_SIINC m_pfnQERApp_QeglobalsSavedinfo_SIInc; - PFN_QEGLOBALSGETGRIDSIZE m_pfnQeglobalsGetGridSize; - PFN_FACELIST_FITTEXTURE m_pfnFaceList_FitTexture; - PFN_GETMAINWINDOW m_pfnGetMainWindow; - PFN_SETWINPOS_FROM_PREFS m_pfnSetWinPos_From_Prefs; - PFN_GETSELECTEDFACECOUNT_BRUSH m_pfnGetSelectedFaceCountfromBrushes; - PFN_GETSELFACESTEXDEF m_pfnGetSelFacesTexdef; - PFN_SETTEXDEF_FACELIST m_pfnSetTexdef_FaceList; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// +// + +#ifndef __ISURFACEPLUGIN_H_ +#define __ISURFACEPLUGIN_H_ + +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; + +#define SURFACEDIALOG_MAJOR "surfdialog" + +// there's a void* in each qtexture_t, must be casted to a IPluginTexdef* +// there's a void* in each face_t, must be casted to a IPluginTexdef* +// NOTE: IPluginTexdef stores a pointer to the qtexture_t or face_t it's stored in +// members of IPluginTexdef often access the qtexture_t or face_t they are connected to + +// Write texdef needs a function pointer, because Radiant either writes into a FILE or a CMemFile +typedef void (* PFN_QERAPP_MAPPRINTF) ( char *text, ... ); + +class IPluginTexdef +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; +}; + + + +// Nurail: For SI module +class texdef_to_face_t +{ +public: + texdef_to_face_t* next; + brush_t *brush; // Brush faces belong to (for Undo) + face_t *face; // Face of Texdef + texdef_t texdef; // Working texdef + texdef_t orig_texdef; // Original, for baselining changes +}; + + +typedef void (* PFN_QERPLUG_DOSURFACE) (); +typedef void (* PFN_QERPLUG_TOGGLESURFACE) (); +typedef void (* PFN_QERPLUG_UPDATESURFACEDIALOG) (); +typedef void (* PFN_QERPLUG_SURFACEDLGFITALL) (); +typedef GtkWidget* (* PFN_GET_SI_MODULE_WIDGET) (); + +struct _QERPlugSurfaceTable +{ + int m_nSize; + PFN_QERPLUG_TOGGLESURFACE m_pfnToggleSurface; + PFN_QERPLUG_DOSURFACE m_pfnDoSurface; + PFN_QERPLUG_UPDATESURFACEDIALOG m_pfnUpdateSurfaceDialog; + PFN_QERPLUG_SURFACEDLGFITALL m_pfnSurfaceDlgFitAll; + PFN_GET_SI_MODULE_WIDGET m_pfnGet_SI_Module_Widget; +}; + +// this one is used by the plugin to access some Radiant stuff + +#define APPSURFACEDIALOG_MAJOR "appsurfdialog" + +// {42BAE4C0-9787-11d3-8EF3-0000E8E8657B} +static const GUID QERAppSurfaceTable_GUID = +{ 0x42bae4c0, 0x9787, 0x11d3, { 0x8e, 0xf3, 0x0, 0x0, 0xe8, 0xe8, 0x65, 0x7b } }; + +typedef bool (* PFN_PATCHESSELECTED) (); +// retrieve g_qeglobals.texturewin_t +//++timo FIXME: this should move in a dedicated table for all g_qeglobals stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN) (); +// look for the first selected patch mesh +//++timo FIXME: this is a convenient func since there's no way to scan patches ( yet ) +typedef patchMesh_t* (* PFN_GETSELECTEDPATCH) (); +//++timo FIXME: this one in particular is a hack +typedef void (* PFN_GETTWOSELECTEDPATCH) (patchMesh_t **p1, patchMesh_t **p2); + + +// leo FIXME: hacks uglier than the ones above +typedef void (* PFN_TEXMATTOFAKETEXCOORDS) (vec_t texMat[2][3], float shift[2], float *rot, float scale[2]); +typedef void (* PFN_CONVERTTEXMATWITHQTEXTURE) (brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2); +typedef void (* PFN_FAKETEXCOORDSTOTEXMAT) (float shift[2], float rot, float scale[2], vec_t texMat[2][3]); +typedef void (* PFN_PATCH_RESETTEXTURING) (float fx, float fy); +typedef void (* PFN_PATCH_FITTEXTURING) (); +typedef void (* PFN_PATCH_NATURALIZESELECTED) (bool bCap); +typedef const char* (* PFN_PATCH_GETTEXTURENAME) (); +typedef qboolean (* PFN_QE_SINGLEBRUSH) (bool bQuiet); +typedef qboolean (* PFN_ISBRUSHPRIMITMODE) (); +typedef void (* PFN_SELECT_FITTEXTURE)(int nHeight, int nWidth); +typedef void (*PFN_COMPUTEAXISBASE)(vec3_t normal,vec3_t texS,vec3_t texT ); +typedef void (*PFN_BPMATMUL)(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); +typedef void (*PFN_EMITBRUSHPRIMITTEXCOORDS)(face_t * f, winding_t * w); +typedef texdef_t* (*PFN_QEGLOBALSSAVEDINFO_SIINC) (); +typedef float (* PFN_QEGLOBALSGETGRIDSIZE) (); +typedef void (* PFN_FACELIST_FITTEXTURE) (texdef_to_face_t* texdef_face_list, int nHeight, int nWidth); +typedef GtkWindow* (* PFN_GETMAINWINDOW)(); +typedef void (* PFN_SETWINPOS_FROM_PREFS) (GtkWidget *win); +typedef int (* PFN_GETSELECTEDFACECOUNT_BRUSH) (); +typedef void (* PFN_GETSELFACESTEXDEF) (texdef_to_face_t *); +typedef void (* PFN_SETTEXDEF_FACELIST) (texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale); +typedef void (* PFN_SETACTIVEINRADIANT) (); + + +struct _QERAppSurfaceTable +{ + int m_nSize; + PFN_PATCHESSELECTED m_pfnOnlyPatchesSelected; + PFN_PATCHESSELECTED m_pfnAnyPatchesSelected; + PFN_GETSELECTEDPATCH m_pfnGetSelectedPatch; + PFN_GETTWOSELECTEDPATCH m_pfnGetTwoSelectedPatch; + PFN_TEXMATTOFAKETEXCOORDS m_pfnTexMatToFakeTexCoords; + PFN_CONVERTTEXMATWITHQTEXTURE m_pfnConvertTexMatWithQTexture; + PFN_FAKETEXCOORDSTOTEXMAT m_pfnFakeTexCoordsToTexMat; + PFN_PATCH_RESETTEXTURING m_pfnPatch_ResetTexturing; + PFN_PATCH_FITTEXTURING m_pfnPatch_FitTexturing; + PFN_PATCH_NATURALIZESELECTED m_pfnPatch_NaturalizeSelected; + PFN_PATCH_GETTEXTURENAME m_pfnPatch_GetTextureName; + PFN_QE_SINGLEBRUSH m_pfnQE_SingleBrush; + PFN_ISBRUSHPRIMITMODE m_pfnIsBrushPrimitMode; + PFN_COMPUTEAXISBASE m_pfnComputeAxisBase; + PFN_BPMATMUL m_pfnBPMatMul; + PFN_EMITBRUSHPRIMITTEXCOORDS m_pfnEmitBrushPrimitTextureCoordinates; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_SELECT_FITTEXTURE m_pfnSelect_FitTexture; + PFN_QEGLOBALSSAVEDINFO_SIINC m_pfnQERApp_QeglobalsSavedinfo_SIInc; + PFN_QEGLOBALSGETGRIDSIZE m_pfnQeglobalsGetGridSize; + PFN_FACELIST_FITTEXTURE m_pfnFaceList_FitTexture; + PFN_GETMAINWINDOW m_pfnGetMainWindow; + PFN_SETWINPOS_FROM_PREFS m_pfnSetWinPos_From_Prefs; + PFN_GETSELECTEDFACECOUNT_BRUSH m_pfnGetSelectedFaceCountfromBrushes; + PFN_GETSELFACESTEXDEF m_pfnGetSelFacesTexdef; + PFN_SETTEXDEF_FACELIST m_pfnSetTexdef_FaceList; +}; + +#endif diff --git a/include/itoolbar.h b/include/itoolbar.h index 05a05559..221938f6 100644 --- a/include/itoolbar.h +++ b/include/itoolbar.h @@ -1,61 +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 __IPLUGTOOLBAR_H_ -#define __IPLUGTOOLBAR_H_ - -/* -NOTE: this API requires Gtk -it's a good practice to avoid putting #include <gtk/gtk.h> here -in some cases, the compiler will get confused because of 'list' identifiers between Gtk and STL headers -*/ - -#define TOOLBAR_MAJOR "toolbar" - -class IToolbarButton -{ -public: - enum EType - { - eSpace, - eButton, - eToggleButton, - eRadioButton, - }; - - virtual const char* getImage() const = 0; - virtual const char* getText() const = 0; - virtual const char* getTooltip() const = 0; - virtual EType getType() const = 0; - virtual void activate() const = 0; -}; - -typedef unsigned int (* PFN_TOOLBARBUTTONCOUNT)(); -typedef const IToolbarButton* (* PFN_GETTOOLBARBUTTON)(unsigned int index); - -struct _QERPlugToolbarTable -{ - int m_nSize; - PFN_TOOLBARBUTTONCOUNT m_pfnToolbarButtonCount; - PFN_GETTOOLBARBUTTON m_pfnGetToolbarButton; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __IPLUGTOOLBAR_H_ +#define __IPLUGTOOLBAR_H_ + +/* +NOTE: this API requires Gtk +it's a good practice to avoid putting #include <gtk/gtk.h> here +in some cases, the compiler will get confused because of 'list' identifiers between Gtk and STL headers +*/ + +#define TOOLBAR_MAJOR "toolbar" + +class IToolbarButton +{ +public: + enum EType + { + eSpace, + eButton, + eToggleButton, + eRadioButton, + }; + + virtual const char* getImage() const = 0; + virtual const char* getText() const = 0; + virtual const char* getTooltip() const = 0; + virtual EType getType() const = 0; + virtual void activate() const = 0; +}; + +typedef unsigned int (* PFN_TOOLBARBUTTONCOUNT)(); +typedef const IToolbarButton* (* PFN_GETTOOLBARBUTTON)(unsigned int index); + +struct _QERPlugToolbarTable +{ + int m_nSize; + PFN_TOOLBARBUTTONCOUNT m_pfnToolbarButtonCount; + PFN_GETTOOLBARBUTTON m_pfnGetToolbarButton; +}; + +#endif diff --git a/include/iui.h b/include/iui.h index 16b7c8cd..d3af6777 100644 --- a/include/iui.h +++ b/include/iui.h @@ -1,158 +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 -*/ - -//----------------------------------------------------------------------------- -// -// DESCRIPTION: -// interface for all-purpose messaging and UI -// window class for MFC, Gtk or Q3 UI -// each version of Radiant implements the API, using the native code that it needs - -#ifndef __IUI_H_ -#define __IUI_H_ - -// this one can be hooked in the GL window procs for customizing GUI through plugins -// the class is implemented by the plugin module, and given to Radiant who calls into it -class IWindowListener -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // since Radiant is MFC we don't use a WNDPROC, we wrap the MFC handlers - // the handler is called first, if returns false Radiant continues processing - //++timo maybe add more later ? OnKeyUp and OnKeyDown for instance - //++timo TODO: add handlers everywhere - // Gef: Changed 2nd & 3rd params to gdouble's for sub-integer grid sizes - virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y) = 0; - virtual bool OnKeyPressed(char *s) = 0; - - // paint message, the caller makes the GL context current, calls Paint, then swaps GL buffers - // return value might be false if something failed and closure is requested .. then the buffer swap will be cancelled - virtual bool Paint() = 0; - // window is closing (nothing you can do, just telling) - virtual void Close() = 0; -}; - -// IWindowListener with additional properties -// NOTE: for now it is both a window and the GL widget -// in the case of Gtk, there are two widgets, the window widget (a container) and the GL widget -class IWindow -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // misc data ------------------------------------------------ - // get pixel size - virtual int getHeight() = 0; - virtual int getWidth() = 0; - // initialisation stuff ------------------------------------- - // set pixel size and other parameters before showing it - virtual void setSizeParm(int width, int height) = 0; - // set the IWindowListener (implemented by the plugin using this window) - virtual void setListener(IWindowListener *) = 0; - // set the window name - virtual void setName(char *) = 0; - // will actually create the GL and the window based on the parameters - virtual bool Show() = 0; - // commands ------------------------------------------------- - // call this to ask for a Redraw - virtual void Redraw() = 0; -}; - -// various Radiant messages -------- -// this one holds the total number of supported messages (this is used to allocate structs) -#define RADIANT_MSGCOUNT 5 -// they start with a 0, can be indexed in an array -// something was selected / deselected -#define RADIANT_SELECTION 0 -// a brush face was selected / deselected -#define RADIANT_SFACE 1 -// current texture / shader changed -#define RADIANT_TEXTURE 2 -// Radiant is going to enter "sleep mode" (all GL contexts will be destroyed) -#define RADIANT_SLEEP 3 -// Radiant has left "sleep mode" (GL contexts are recreated) -#define RADIANT_WAKEUP 4 - - -// this one can be used to listen for Radiant-specific events, not related to a window -class IListener -{ -public: - // Increment the number of references to this object - virtual void IncRef () = 0; - // Decrement the reference count - virtual void DecRef () = 0; - // message is one of the RADIANT_* consts - virtual void DispatchRadiantMsg( int Msg ) = 0; -}; - -// this one is provided by Radiant, it's a wrapper for some usefull functions -class IXYWndWrapper -{ -public: - virtual void SnapToGrid( int x1, int y1, vec3_t pt ) = 0; - virtual VIEWTYPE GetViewType( void ) = 0; -}; - -#define UI_MAJOR "ui" - -// create an IWindow with GL context -typedef IWindow* (WINAPI* PFN_QERAPP_CREATEGLWINDOW) (); - -// will hook the given IWindowListener to the XY window and increment the ref count -//++timo TODO: add hooking in the CAM view and Z view -typedef void (WINAPI* PFN_QERAPP_HOOKWINDOW) (IWindowListener *); -// will unhook the given IWindowListener -typedef void (WINAPI* PFN_QERAPP_UNHOOKWINDOW) (IWindowListener *); -// to retrieve the IXYWndWrapper -typedef IXYWndWrapper* (WINAPI* PFN_QERAPP_GETXYWNDWRAPPER) (); - -// will hook a given listener into Radiant listening for the given message and increment ref count -// call several times to listen for several messages -typedef void (WINAPI* PFN_QERAPP_HOOKLISTENER) (IListener *, int Msg); -// will unhook the listener and return the number of messages the given listener was removed from -typedef int (WINAPI* PFN_QERAPP_UNHOOKLISTENER)(IListener *); - -// TODO: create GL widget, destroy it - -struct _QERUITable -{ - int m_nSize; - PFN_QERAPP_CREATEGLWINDOW m_pfnCreateGLWindow; - PFN_QERAPP_HOOKWINDOW m_pfnHookWindow; - PFN_QERAPP_UNHOOKWINDOW m_pfnUnHookWindow; - PFN_QERAPP_GETXYWNDWRAPPER m_pfnGetXYWndWrapper; - PFN_QERAPP_HOOKLISTENER m_pfnHookListener; - PFN_QERAPP_UNHOOKLISTENER m_pfnUnHookListener; -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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: +// interface for all-purpose messaging and UI +// window class for MFC, Gtk or Q3 UI +// each version of Radiant implements the API, using the native code that it needs + +#ifndef __IUI_H_ +#define __IUI_H_ + +// this one can be hooked in the GL window procs for customizing GUI through plugins +// the class is implemented by the plugin module, and given to Radiant who calls into it +class IWindowListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // since Radiant is MFC we don't use a WNDPROC, we wrap the MFC handlers + // the handler is called first, if returns false Radiant continues processing + //++timo maybe add more later ? OnKeyUp and OnKeyDown for instance + //++timo TODO: add handlers everywhere + // Gef: Changed 2nd & 3rd params to gdouble's for sub-integer grid sizes + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnKeyPressed(char *s) = 0; + + // paint message, the caller makes the GL context current, calls Paint, then swaps GL buffers + // return value might be false if something failed and closure is requested .. then the buffer swap will be cancelled + virtual bool Paint() = 0; + // window is closing (nothing you can do, just telling) + virtual void Close() = 0; +}; + +// IWindowListener with additional properties +// NOTE: for now it is both a window and the GL widget +// in the case of Gtk, there are two widgets, the window widget (a container) and the GL widget +class IWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // misc data ------------------------------------------------ + // get pixel size + virtual int getHeight() = 0; + virtual int getWidth() = 0; + // initialisation stuff ------------------------------------- + // set pixel size and other parameters before showing it + virtual void setSizeParm(int width, int height) = 0; + // set the IWindowListener (implemented by the plugin using this window) + virtual void setListener(IWindowListener *) = 0; + // set the window name + virtual void setName(char *) = 0; + // will actually create the GL and the window based on the parameters + virtual bool Show() = 0; + // commands ------------------------------------------------- + // call this to ask for a Redraw + virtual void Redraw() = 0; +}; + +// various Radiant messages -------- +// this one holds the total number of supported messages (this is used to allocate structs) +#define RADIANT_MSGCOUNT 5 +// they start with a 0, can be indexed in an array +// something was selected / deselected +#define RADIANT_SELECTION 0 +// a brush face was selected / deselected +#define RADIANT_SFACE 1 +// current texture / shader changed +#define RADIANT_TEXTURE 2 +// Radiant is going to enter "sleep mode" (all GL contexts will be destroyed) +#define RADIANT_SLEEP 3 +// Radiant has left "sleep mode" (GL contexts are recreated) +#define RADIANT_WAKEUP 4 + + +// this one can be used to listen for Radiant-specific events, not related to a window +class IListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // message is one of the RADIANT_* consts + virtual void DispatchRadiantMsg( int Msg ) = 0; +}; + +// this one is provided by Radiant, it's a wrapper for some usefull functions +class IXYWndWrapper +{ +public: + virtual void SnapToGrid( int x1, int y1, vec3_t pt ) = 0; + virtual VIEWTYPE GetViewType( void ) = 0; +}; + +#define UI_MAJOR "ui" + +// create an IWindow with GL context +typedef IWindow* (WINAPI* PFN_QERAPP_CREATEGLWINDOW) (); + +// will hook the given IWindowListener to the XY window and increment the ref count +//++timo TODO: add hooking in the CAM view and Z view +typedef void (WINAPI* PFN_QERAPP_HOOKWINDOW) (IWindowListener *); +// will unhook the given IWindowListener +typedef void (WINAPI* PFN_QERAPP_UNHOOKWINDOW) (IWindowListener *); +// to retrieve the IXYWndWrapper +typedef IXYWndWrapper* (WINAPI* PFN_QERAPP_GETXYWNDWRAPPER) (); + +// will hook a given listener into Radiant listening for the given message and increment ref count +// call several times to listen for several messages +typedef void (WINAPI* PFN_QERAPP_HOOKLISTENER) (IListener *, int Msg); +// will unhook the listener and return the number of messages the given listener was removed from +typedef int (WINAPI* PFN_QERAPP_UNHOOKLISTENER)(IListener *); + +// TODO: create GL widget, destroy it + +struct _QERUITable +{ + int m_nSize; + PFN_QERAPP_CREATEGLWINDOW m_pfnCreateGLWindow; + PFN_QERAPP_HOOKWINDOW m_pfnHookWindow; + PFN_QERAPP_UNHOOKWINDOW m_pfnUnHookWindow; + PFN_QERAPP_GETXYWNDWRAPPER m_pfnGetXYWndWrapper; + PFN_QERAPP_HOOKLISTENER m_pfnHookListener; + PFN_QERAPP_UNHOOKLISTENER m_pfnUnHookListener; +}; + +#endif diff --git a/include/iui_gtk.h b/include/iui_gtk.h index 5cd820c4..93973672 100644 --- a/include/iui_gtk.h +++ b/include/iui_gtk.h @@ -1,59 +1,59 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 -// This contains functions specific to the UI toolkit -// it is best to avoid using them, but they are provided for backward compatibility with the older interfaces -// the abstracted UI layer in iUI.h is not sufficient for some tasks .. no other choice than to rely on UI specific code - -#ifndef __IGL_GTK_H__ -#define __IGL_GTK_H__ - -#define UIGTK_MAJOR "uigtk" - -// All OpenGL stuff is handled by GLWidget to ensure portability -typedef GtkWidget* (WINAPI* PFN_QERAPP_GETQEGLOBALSGLWIDGET) (); -typedef GtkWidget* (WINAPI* PFN_GLWIDGET_NEW) (gboolean zbufffer, GtkWidget* share); -typedef void (WINAPI* PFN_GLWIDGET_SWAPBUFFERS) (GtkWidget* widget); -typedef gboolean (WINAPI* PFN_GLWIDGET_MAKECURRENT) (GtkWidget* widget); -typedef void (WINAPI* PFN_GLWIDGET_DESTROYCONTEXT) (GtkWidget* widget); -typedef void (WINAPI* PFN_GLWIDGET_CREATECONTEXT) (GtkWidget* widget); -#if 0 -typedef gpointer (WINAPI* PFN_GLWIDGET_GETCONTEXT) (GtkWidget* widget); -#endif - -struct _QERUIGtkTable -{ - int m_nSize; - PFN_QERAPP_GETQEGLOBALSGLWIDGET m_pfn_GetQeglobalsGLWidget; - PFN_GLWIDGET_NEW m_pfn_glwidget_new; - PFN_GLWIDGET_SWAPBUFFERS m_pfn_glwidget_swap_buffers; - PFN_GLWIDGET_MAKECURRENT m_pfn_glwidget_make_current; - PFN_GLWIDGET_DESTROYCONTEXT m_pfn_glwidget_destroy_context; - PFN_GLWIDGET_CREATECONTEXT m_pfn_glwidget_create_context; -#if 0 - PFN_GLWIDGET_GETCONTEXT m_pfn_glwidget_get_context; -#endif -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 +// This contains functions specific to the UI toolkit +// it is best to avoid using them, but they are provided for backward compatibility with the older interfaces +// the abstracted UI layer in iUI.h is not sufficient for some tasks .. no other choice than to rely on UI specific code + +#ifndef __IGL_GTK_H__ +#define __IGL_GTK_H__ + +#define UIGTK_MAJOR "uigtk" + +// All OpenGL stuff is handled by GLWidget to ensure portability +typedef GtkWidget* (WINAPI* PFN_QERAPP_GETQEGLOBALSGLWIDGET) (); +typedef GtkWidget* (WINAPI* PFN_GLWIDGET_NEW) (gboolean zbufffer, GtkWidget* share); +typedef void (WINAPI* PFN_GLWIDGET_SWAPBUFFERS) (GtkWidget* widget); +typedef gboolean (WINAPI* PFN_GLWIDGET_MAKECURRENT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_DESTROYCONTEXT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_CREATECONTEXT) (GtkWidget* widget); +#if 0 +typedef gpointer (WINAPI* PFN_GLWIDGET_GETCONTEXT) (GtkWidget* widget); +#endif + +struct _QERUIGtkTable +{ + int m_nSize; + PFN_QERAPP_GETQEGLOBALSGLWIDGET m_pfn_GetQeglobalsGLWidget; + PFN_GLWIDGET_NEW m_pfn_glwidget_new; + PFN_GLWIDGET_SWAPBUFFERS m_pfn_glwidget_swap_buffers; + PFN_GLWIDGET_MAKECURRENT m_pfn_glwidget_make_current; + PFN_GLWIDGET_DESTROYCONTEXT m_pfn_glwidget_destroy_context; + PFN_GLWIDGET_CREATECONTEXT m_pfn_glwidget_create_context; +#if 0 + PFN_GLWIDGET_GETCONTEXT m_pfn_glwidget_get_context; +#endif +}; + +#endif diff --git a/include/iundo.h b/include/iundo.h index d5194b52..b4fffeec 100644 --- a/include/iundo.h +++ b/include/iundo.h @@ -1,87 +1,87 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IUNDO_H_ -#define _IUNDO_H_ - -#define UNDO_MAJOR "undo" - -//start operation -typedef void (*PFN_UNDOSTART) (char *operation); -//end operation -typedef void (*PFN_UNDOEND) (void); -//add brush to the undo -typedef void (*PFN_UNDOADDBRUSH) (brush_t *pBrush); -//end a brush after the operation is performed -typedef void (*PFN_UNDOENDBRUSH) (brush_t *pBrush); -//add a list with brushes to the undo -typedef void (*PFN_UNDOADDBRUSHLIST) (brush_t *brushlist); -//end a list with brushes after the operation is performed -typedef void (*PFN_UNDOENDBRUSHLIST) (brush_t *brushlist); -//add entity to undo -typedef void (*PFN_UNDOADDENTITY) (entity_t *entity); -//end an entity after the operation is performed -typedef void (*PFN_UNDOENDENTITY) (entity_t *entity); -//undo last operation (bSilent == true -> will not print the "undone blah blah message") -typedef void (*PFN_UNDO) (unsigned char bSilent); -//redo last undone operation -typedef void (*PFN_REDO) (void); -//get the undo Id of the next undo (0 if none available) -typedef int (*PFN_GETUNDOID) (void); -//returns true if there is something to be undone available -typedef int (*PFN_UNDOAVAILABLE) (void); -//returns true if there is something to redo available -typedef int (*PFN_REDOAVAILABLE) (void); - -struct _QERUndoTable -{ - int m_nSize; - PFN_UNDOSTART m_pfnUndo_Start; - PFN_UNDOEND m_pfnUndo_End; - PFN_UNDOADDBRUSH m_pfnUndo_AddBrush; - PFN_UNDOENDBRUSH m_pfnUndo_EndBrush; - PFN_UNDOADDBRUSHLIST m_pfnUndo_AddBrushList; - PFN_UNDOENDBRUSHLIST m_pfnUndo_EndBrushList; - PFN_UNDOADDENTITY m_pfnUndo_AddEntity; - PFN_UNDOENDENTITY m_pfnUndo_EndEntity; - PFN_UNDO m_pfnUndo_Undo; - PFN_REDO m_pfnUndo_Redo; - PFN_GETUNDOID m_pfnUndo_GetUndoId; - PFN_UNDOAVAILABLE m_pfnUndo_UndoAvailable; - PFN_REDOAVAILABLE m_pfnUndo_RedoAvailable; -}; - -#ifdef USE_UNDOTABLE_DEFINE -#ifndef __UNDOTABLENAME -#define __UNDOTABLENAME g_UndoTable -#endif -#define Undo_Start __UNDOTABLENAME.m_pfnUndo_Start -#define Undo_End __UNDOTABLENAME.m_pfnUndo_End -#define Undo_AddBrush __UNDOTABLENAME.m_pfnUndo_AddBrush -#define Undo_EndBrush __UNDOTABLENAME.m_pfnUndo_EndBrush -#define Undo_AddBrushList __UNDOTABLENAME.m_pfnUndo_AddBrushList -#define Undo_EndBrushList __UNDOTABLENAME.m_pfnUndo_EndBrushList -#define Undo_AddEntity __UNDOTABLENAME.m_pfnUndo_AddEntity -#define Undo_EndEntity __UNDOTABLENAME.m_pfnUndo_EndEntity -#endif - -#endif // _IUNDO_H_ - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IUNDO_H_ +#define _IUNDO_H_ + +#define UNDO_MAJOR "undo" + +//start operation +typedef void (*PFN_UNDOSTART) (char *operation); +//end operation +typedef void (*PFN_UNDOEND) (void); +//add brush to the undo +typedef void (*PFN_UNDOADDBRUSH) (brush_t *pBrush); +//end a brush after the operation is performed +typedef void (*PFN_UNDOENDBRUSH) (brush_t *pBrush); +//add a list with brushes to the undo +typedef void (*PFN_UNDOADDBRUSHLIST) (brush_t *brushlist); +//end a list with brushes after the operation is performed +typedef void (*PFN_UNDOENDBRUSHLIST) (brush_t *brushlist); +//add entity to undo +typedef void (*PFN_UNDOADDENTITY) (entity_t *entity); +//end an entity after the operation is performed +typedef void (*PFN_UNDOENDENTITY) (entity_t *entity); +//undo last operation (bSilent == true -> will not print the "undone blah blah message") +typedef void (*PFN_UNDO) (unsigned char bSilent); +//redo last undone operation +typedef void (*PFN_REDO) (void); +//get the undo Id of the next undo (0 if none available) +typedef int (*PFN_GETUNDOID) (void); +//returns true if there is something to be undone available +typedef int (*PFN_UNDOAVAILABLE) (void); +//returns true if there is something to redo available +typedef int (*PFN_REDOAVAILABLE) (void); + +struct _QERUndoTable +{ + int m_nSize; + PFN_UNDOSTART m_pfnUndo_Start; + PFN_UNDOEND m_pfnUndo_End; + PFN_UNDOADDBRUSH m_pfnUndo_AddBrush; + PFN_UNDOENDBRUSH m_pfnUndo_EndBrush; + PFN_UNDOADDBRUSHLIST m_pfnUndo_AddBrushList; + PFN_UNDOENDBRUSHLIST m_pfnUndo_EndBrushList; + PFN_UNDOADDENTITY m_pfnUndo_AddEntity; + PFN_UNDOENDENTITY m_pfnUndo_EndEntity; + PFN_UNDO m_pfnUndo_Undo; + PFN_REDO m_pfnUndo_Redo; + PFN_GETUNDOID m_pfnUndo_GetUndoId; + PFN_UNDOAVAILABLE m_pfnUndo_UndoAvailable; + PFN_REDOAVAILABLE m_pfnUndo_RedoAvailable; +}; + +#ifdef USE_UNDOTABLE_DEFINE +#ifndef __UNDOTABLENAME +#define __UNDOTABLENAME g_UndoTable +#endif +#define Undo_Start __UNDOTABLENAME.m_pfnUndo_Start +#define Undo_End __UNDOTABLENAME.m_pfnUndo_End +#define Undo_AddBrush __UNDOTABLENAME.m_pfnUndo_AddBrush +#define Undo_EndBrush __UNDOTABLENAME.m_pfnUndo_EndBrush +#define Undo_AddBrushList __UNDOTABLENAME.m_pfnUndo_AddBrushList +#define Undo_EndBrushList __UNDOTABLENAME.m_pfnUndo_EndBrushList +#define Undo_AddEntity __UNDOTABLENAME.m_pfnUndo_AddEntity +#define Undo_EndEntity __UNDOTABLENAME.m_pfnUndo_EndEntity +#endif + +#endif // _IUNDO_H_ + diff --git a/include/misc_def.h b/include/misc_def.h index ea5a600b..c6ab2ebb 100644 --- a/include/misc_def.h +++ b/include/misc_def.h @@ -1,64 +1,64 @@ -#ifndef _WIN32 - -#define WINAPI -#define APIENTRY - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; -typedef char* LPSTR; - -#define IsEqualGUID(a,b) (memcmp(&a,&b,sizeof(a)) == 0) - -#ifndef GUID_DEFINED -#define GUID_DEFINED -typedef struct _GUID -{ - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -} GUID; -#endif - -#if defined(__cplusplus) -#ifndef _REFGUID_DEFINED -#define _REFGUID_DEFINED -#define REFGUID const GUID & -#endif // !_REFGUID_DEFINED -#endif - -// Message box constants -#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 - -#endif +#ifndef _WIN32 + +#define WINAPI +#define APIENTRY + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef char* LPSTR; + +#define IsEqualGUID(a,b) (memcmp(&a,&b,sizeof(a)) == 0) + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +// Message box constants +#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 + +#endif diff --git a/include/qerplugin.h b/include/qerplugin.h index 907a4bee..e6f1a96e 100644 --- a/include/qerplugin.h +++ b/include/qerplugin.h @@ -1,787 +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 -*/ - -// QERadiant PlugIns -// -// - -#ifndef __QERPLUGIN_H__ -#define __QERPLUGIN_H__ - -/*! -\todo this header is intended to be turned into a header for the core editor functionality -some portability related code should be moved to synapse (such as the GUID stuff) -*/ - -#include <stdio.h> -#include <string.h> -// TTimo -// ideally the plugin API would be UI toolkit independent, but removing the dependency with GLib seems tricky right now.. -#include <glib.h> -#include "qertypes.h" - -// FIXME TTimo: -// GUID declaration here should be trashed, it is in synapse.h -#ifdef _WIN32 -#include <wtypes.h> -#endif - -#define QER_MAX_NAMELEN 1024 - -#ifndef _WIN32 -#include "misc_def.h" -#endif - -// the editor will look for plugins in two places, the plugins path -// under the application path, and the path under the basepath as defined -// in the project (.qe4) file. -// -// you can drop any number of new texture, model format DLL's in the standard plugin path -// but only one plugin that overrides map loading/saving, surface dialog, surface flags, etc.. -// should be used at one time.. if multiples are loaded then the last one loaded will be the -// active one -// -// type of services the plugin supplies, pass any combo of these flags -// it is assumed the plugin will have a matching function as defined below -// to correlate to the implied functionality -// - -#define RADIANT_MAJOR "radiant" - -// basics -#define QERPLUG_INIT "QERPlug_Init" -#define QERPLUG_GETNAME "QERPlug_GetName" -#define QERPLUG_GETCOMMANDLIST "QERPlug_GetCommandList" -#define QERPLUG_DISPATCH "QERPlug_Dispatch" -#define QERPLUG_GETFUNCTABLE "QERPlug_GetFuncTable" - -// game stuff -#define QERPLUG_GETTEXTUREINFO "QERPlug_GetTextureInfo" // gets a texture info structure -#define QERPLUG_LOADTEXTURE "QERPlug_LoadTexture" // loads a texture, will return an RGBA structure - // and any surface flags/contents for it -#define QERPLUG_GETSURFACEFLAGS "QERPlug_GetSurfaceFlags" // gets a list of surface/content flag names from a plugin - -struct _QERTextureInfo -{ - char m_TextureExtension[QER_MAX_NAMELEN]; // the extension these textures have - qboolean m_bHiColor; // if textures are NOT high color, the default - // palette (as described inthe qe4 file will be used for gamma correction) - // if they are high color, gamma and shading are computed on the fly - // based on the rgba data - //--bool m_bIsShader; // will probably do q3 shaders this way when i merge - qboolean m_bWadStyle; // if this is true, the plugin will be presented with the texture path - // defined in the .qe4 file and is expected to preload all the textures - qboolean m_bHalfLife; // causes brushes to be saved/parsed without the surface contents/flags/value -}; - -struct _QERTextureLoad // returned by a plugin -{ - _QERTextureLoad() - { - memset(reinterpret_cast<void*>(this), 0, sizeof(_QERTextureLoad)); - }; - - ~_QERTextureLoad() - { - delete []m_pRGBA; - delete []m_pName; - }; - - void makeSpace(int nSize) - { - m_pRGBA = new unsigned char[nSize+1]; - }; - - void setName(const char* p) - { - m_pName = new char[strlen(p)+1]; - strcpy(m_pName, p); - }; - - - unsigned char *m_pRGBA; // rgba data (alpha channel is supported and drawn appropriately) - int m_nWidth; // width - int m_nHeight; // height - int m_nContents; // default contents - int m_nFlags; // "" flags - int m_nValue; // "" value - char *m_pName; // name to be referenced in map, build tools, etc. -}; - -struct _QERModelInfo -{ - char m_ModelExtension[QER_MAX_NAMELEN]; - bool m_bSkinned; - bool m_bMultipart; -}; - -struct _QERModelLoad -{ - // vertex and skin data -}; - - -//========================================= -// plugin functions -#if 0 -// NOTE TTimo: hack to make old plugin tech and new plugin tech live together -#ifndef _IPLUGIN_H_ -// toolkit-independant interface, cast hwndMain to GtkWidget* -typedef const char* (WINAPI *PFN_QERPLUG_INIT)(void* hApp, void* hwndMain); -typedef const char* (WINAPI *PFN_QERPLUG_GETNAME)(); -typedef const char* (WINAPI *PFN_QERPLUG_GETCOMMANDLIST)(); -typedef void (WINAPI *PFN_QERPLUG_DISPATCH)(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush); -#endif -#endif - -typedef char* (WINAPI *PFN_QERPLUG_GETFUNCTABLE)(); - -// v1.5 -// -// Texture loading -// returns a ptr to _QERTextureInfo -typedef void* (WINAPI *PFN_QERPLUG_GETTEXTUREINFO)(); -// -// loads a texture by calling the texture load func in the editor (defined below) -// transparency (for water, fog, lava, etc.. ) can be emulated in the editor -// by passing in appropriate alpha data or by setting the appropriate surface flags -// expected by q2 (which the editor will use.. ) -typedef void (WINAPI *PFN_QERPLUG_LOADTEXTURE)(const char* pFilename); - -// v1.6 -typedef void* (WINAPI *PFN_QERPLUG_GETSURFACEFLAGS)(); - -// v1.7 -// if exists in plugin, gets called between INIT and GETCOMMANDLIST -// the plugin can register the EClasses he wants to handle -//++timo TODO: this has got to move into the table, and be requested by QERPlug_RequestInterface -//++timo FIXME: the LPVOID parameter must be casted to an IEpair interface -#define QERPLUG_REGISTERPLUGINENTITIES "QERPlug_RegisterPluginEntities" -typedef void (WINAPI * PFN_QERPLUG_REGISTERPLUGINENTITIES)( void* ); - -// if exists in plugin, gets called between INIT and GETCOMMANDLIST -// the plugin can Init all it needs for surface properties -#define QERPLUG_INITSURFACEPROPERTIES "QERPlug_InitSurfaceProperties" -typedef void (WINAPI * PFN_QERPLUG_INITSURFACEPROPERTIES)(); - -// if Radiant needs to use a particular set of commands, it can request the plugin to fill a func table -// this is similar to PFN_QERAPP_REQUESTINTERFACE -#define QERPLUG_REQUESTINTERFACE "QERPlug_RequestInterface" -typedef int (WINAPI * PFN_QERPLUG_REQUESTINTERFACE) (REFGUID refGUID, void* pInterface, const char *version_name); - -// Load an image file -typedef void (* PFN_QERAPP_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); - -// TTimo FIXME: the logic for this is in synapse now - -// MODULES specific: -// if it exports this entry point, will be considered as a module -// a module is a plugin that provides some REQUIRED interfaces to Radiant, such as the shader module -// Radiant will call QERPLUG_LISTINTERFACES to get a list of the interfaces a given plugin implements -// then it will call PFN_QERPLUG_REQUESTINTERFACE to actually get them - -// following leo's code .. looks ok to use a string to identify the various versions of a same interface -// obviously it would be handy to have the same string naming for the interfaces. -// best way would be to have the names come in when you list the interfaces -// NOTE: we might have a problem with the order in which the interfaces are filled in -// there's some kind of dependency graph, the shader module expects to find the VFS ready etc. -typedef struct moduleentry_s { - const GUID *interface_GUID; - const char* interface_name; - const char* version_name; -} moduleentry_t; - -#define QERPLUG_LISTINTERFACES "QERPlug_ListInterfaces" -#define MAX_QERPLUG_INTERFACES 10 -typedef int (WINAPI* PFN_QERPLUG_LISTINTERFACES) (moduleentry_t table[MAX_QERPLUG_INTERFACES]); - -// ======================================== -// GTK+ helper functions - -// NOTE: parent can be NULL in all functions but it's best to set them - -// simple Message Box, see above for the 'type' flags -// toolkit-independent, cast parent ot a GtkWidget* -typedef gint (WINAPI* PFN_QERAPP_MESSAGEBOX) (void *parent, const char* text, - const char* caption, guint32 type, const char *URL); - -// file and directory selection functions return NULL if the user hits cancel -// or a gchar* string that must be g_free'd by the user -// - 'title' is the dialog title (can be NULL) -// - 'path' is used to set the initial directory (can be NULL) -// - 'pattern': the first pattern is for the win32 mode, then comes the Gtk pattern list, see Radiant source for samples -// TTimo 04/01/2001 toolkit-independant, cast parent to a GtkWidget* -typedef const gchar* (* PFN_QERAPP_FILEDIALOG) (void *parent, gboolean open, const char* title, - const char* path, const char* pattern); -typedef gchar* (WINAPI* PFN_QERAPP_DIRDIALOG) (void *parent, const char* title, - const char* path); - -// return true if the user closed the dialog with 'Ok' -// 'color' is used to set the initial value and store the selected value -typedef bool (WINAPI* PFN_QERAPP_COLORDIALOG) (void *parent, float *color, - const char* title); - -// load a .bmp file and store the results in 'gdkpixmap' and 'mask' -// returns TRUE on success but even if it fails, it creates an empty pixmap -// NOTE: 'filename' is relative to <radiant_path>/plugins/bitmaps/ -// TTimo 04/01/2001 toolkit-independant, cast gkpixmap to GdkPixmap and mask to GdkBitmap -typedef bool (WINAPI* PFN_QERAPP_LOADBITMAP) (const char* filename, void **gdkpixmap, void **mask); - -// ======================================== -// read/write preferences file - -// use this function to get the directory where the preferences file are stored -typedef const char* (WINAPI* PFN_QERAPP_PROFILE_GETDIR) (); - -// 'filename' is the absolute path -typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVEINT) (const char *filename, const char *section, - const char *key, int value); -typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVESTR) (const char *filename, const char *section, - const char *key, const char *value); -typedef int (WINAPI* PFN_QERAPP_PROFILE_LOADINT) (const char *filename, const char *section, - const char *key, int default_value); -typedef char* (WINAPI* PFN_QERAPP_PROFILE_LOADSTR) (const char *filename, const char *section, - const char *key, const char *default_value); - -//========================================= -// editor functions - -// There are 3 potential brush handle lists -// 1. the list that contains brushes a plugin creates using CreateBrushHandle -// 2. the selected brush list (brushes the user has selected) -// 3. the active brush list (brushes in the map that are not selected) -// -// In general, the same things can be done to brush handles (face manip, delete brushhandle, etc.. ) in each -// list. There are a few exceptions. -// 1. You cannot commit a selected or active brush handle to the map. This is because it is already in the map. -// 2. You cannot bind brush handles from the selected or active brush list to an entity. As of v1.0 of the plugins -// the only way for a plugin to create entities is to create a brush handles (or a list of handles) and then bind -// them to an entity. This will commit the brush(s) and/or the entities to the map as well. -// -// To use the active or selected brush lists, you must first allocate them (which returns a count) and then -// release them when you are finish manipulating brushes in one of those lists. - -//++timo NOTE : the #defines here are never used, but can help finding where things are done in the editor -#if 0 -// brush manipulation routines -#define QERAPP_CREATEBRUSH "QERApp_CreateBrush" -#define QERAPP_CREATEBRUSHHANDLE "QERApp_CreateBrushHandle" -#define QERAPP_DELETEBRUSHHANDLE "QERApp_DeleteBrushHandle" -#define QERAPP_COMMITBRUSHHANDLETOMAP "QERApp_CommitBrushHandleToMap" -//++timo not implemented .. remove -// #define QERAPP_BINDHANDLESTOENTITY "QERApp_BindHandlesToEntity" -#define QERAPP_ADDFACE "QERApp_AddFace" -#define QERAPP_ADDFACEDATA "QERApp_AddFaceData" -#define QERAPP_GETFACECOUNT "QERApp_GetFaceCount" -#define QERAPP_GETFACEDATA "QERApp_GetFaceData" -#define QERAPP_SETFACEDATA "QERApp_SetFaceData" -#define QERAPP_DELETEFACE "QERApp_DeleteFace" -#define QERAPP_TEXTUREBRUSH "QERApp_TextureBrush" -#define QERAPP_BUILDBRUSH "QERApp_BuildBrush" // PGM -#define QERAPP_SELECTEDBRUSHCOUNT "QERApp_SelectedBrushCount" -#define QERAPP_ALLOCATESELECTEDBRUSHHANDLES "QERApp_AllocateSelectedBrushHandles" -#define QERAPP_RELEASESELECTEDBRUSHHANDLES "QERApp_ReleaseSelectedBrushHandles" -#define QERAPP_GETSELECTEDBRUSHHANDLE "QERApp_GetSelectedBrushHandle" -#define QERAPP_ACTIVEBRUSHCOUNT "QERApp_ActiveBrushCount" -#define QERAPP_ALLOCATEACTIVEBRUSHHANDLES "QERApp_AllocateActiveBrushHandles" -#define QERAPP_RELEASEACTIVEBRUSHHANDLES "QERApp_ReleaseActiveBrushHandles" -#define QERAPP_GETACTIVEBRUSHHANDLE "QERApp_GetActiveBrushHandle" - -// texture stuff -#define QERAPP_TEXTURECOUNT "QERApp_TextureCount" -#define QERAPP_GETTEXTURE "QERApp_GetTexture" -#define QERAPP_GETCURRENTTEXTURE "QERApp_GetCurrentTexture" -#define QERAPP_SETCURRENTTEXTURE "QERApp_SetCurrentTexture" - -// selection -#define QERAPP_DELETESELECTION "QERApp_DeleteSelection" -#define QERAPP_SELECTBRUSH "QERApp_SelectBrush" // PGM -#define QERAPP_DESELECTBRUSH "QERApp_DeselectBrush" // PGM -#define QERAPP_DESELECTALLBRUSHES "QERApp_DeselectAllBrushes" // PGM - -// data gathering -#define QERAPP_GETPOINTS "QERApp_GetPoints" -#define QERAPP_SELECTBRUSHES "QERApp_GetBrushes" - -// entity class stuff -// the entity handling is very basic for 1.0 -#define QERAPP_GETECLASSCOUNT "QERApp_GetEClassCount" -#define QERAPP_GETECLASS "QERApp_GetEClass" - -// misc -#define QERAPP_SYSMSG "QERApp_SysMsg" -#define QERAPP_INFOMSG "QERApp_InfoMsg" -#define QERAPP_HIDEINFOMSG "QERApp_HideInfoMsg" -#define QERAPP_RESET_PLUGINS "QERApp_ResetPlugins" - -// texture loading -#define QERAPP_LOADTEXTURERGBA "QERApp_LoadTextureRGBA" - -// FIXME: the following are not implemented yet -// hook registrations -#define QERAPP_REGISTER_MAPLOADFUNC "QERApp_Register_MapLoadFunc" -#define QERAPP_REGISTER_MAPSAVEFUNC "QERApp_Register_MapSaveFunc" - -// FIXME: the following are not implemented yet -#define QERAPP_REGISTER_PROJECTLOADFUNC "QERApp_Register_ProjectLoadFunc" -#define QERAPP_REGISTER_MOUSEHANDLER "QERApp_Register_MouseHandler" -#define QERAPP_REGISTER_KEYHANDLER "QERApp_Register_KeyHandler" - -// FIXME: new primtives do not work in v1.00 -// primitives are new types of things in the map -// for instance, the Q3 curves could have been done as -// primitives instead of being built in -// it will be a plugins responsibility to hook the map load and save funcs to load -// and/or save any additional data (like new primitives of some type) -// the editor will call each registered renderer during the rendering process to repaint -// any primitives the plugin owns -// each primitive object has a temporary sibling brush that lives in the map -// FIXME: go backwards on this a bit.. orient it more towards the temp brush mode as it will be cleaner -// basically a plugin will hook the map load and save and will add the primitives to the map.. this will -// produce a temporary 'primitive' brush and the appropriate renderer will be called as well as the -// edit handler (for edge drags, sizes, rotates, etc.. ) and the vertex maker will be called when vertex -// mode is attemped on the brush.. there will need to be a GetPrimitiveBounds callback in the edit handler -// so the brush can resize appropriately as needed.. this might be the plugins responsibility to set the -// sibling brushes size.. it will then be the plugins responsibility to hook map save to save the primitives -// as the editor will discard any temp primitive brushes.. (there probably needs to be some kind of sanity check -// here as far as keeping the brushes and the plugin in sync.. i suppose the edit handler can deal with all of that -// crap but it looks like a nice place for a mess) -#define QERAPP_REGISTER_PRIMITIVE "QERApp_Register_Primitive" -#define QERAPP_REGISTER_RENDERER "QERApp_Register_Renderer" -#define QERAPP_REGISTER_EDITHANDLER "QERApp_Register_EditHandler" -#define QERAPP_REGISTER_VERTEXMAKER "QERApp_Register_VertexMaker" -#define QERAPP_ADDPRIMITIVE "QERApp_AddPrimitive" - -// v1.70 -#define QERAPP_GETENTITYCOUNT "QERApp_GetEntityCount" -#define QERAPP_GETENTITYHANDLE "QERApp_GetEntityHandle" -//++timo not implemented for the moment -// #define QERAPP_GETENTITYINFO "QERApp_GetEntityInfo" -//++timo does the keyval need some more funcs to add/remove ? -// get the pointer and do the changes yourself -#define QERAPP_ALLOCATEEPAIR "QERApp_AllocateEpair" -#define QERAPP_ALLOCATEENTITYBRUSHHANDLES "QERApp_AllocateEntityBrushHandles" -#define QERAPP_RELEASEENTITYBRUSHHANDLES "QERApp_ReleaseEntityBrushHandles" -#define QERAPP_GETENTITYBRUSHHANDLE "QERApp_GetEntityBrushHandle" -#define QERAPP_CREATEENTITYHANDLE "QERApp_CreateEntityHandle" -#define QERAPP_COMMITBRUSHHANDLETOENTITY "QERApp_CommitBrushHandleToEntity" -#define QERAPP_COMMITENTITYHANDLETOMAP "QERApp_CommitEntityHandleToMap" -#define QERAPP_SETSCREENUPDATE "QERApp_SetScreenUpdate" -#define QERAPP_BUILDBRUSH2 "QERApp_BuildBrush2" -#endif - -// v1.80 -#define QERAPP_GETDISPATCHPARAMS "QERApp_GetDispatchParams" - -struct _QERPointData -{ - int m_nCount; - vec3_t *m_pVectors; -}; - -struct _QERFaceData -{ - char m_TextureName[QER_MAX_NAMELEN]; - int m_nContents; - int m_nFlags; - int m_nValue; - float m_fShift[2]; - float m_fRotate; - float m_fScale[2]; - vec3_t m_v1, m_v2, m_v3; - // brush primitive additions - qboolean m_bBPrimit; - brushprimit_texdef_t brushprimit_texdef; -}; - -typedef void (WINAPI * PFN_QERAPP_CREATEBRUSH)(vec3_t vMin, vec3_t vMax); - -typedef void* (WINAPI * PFN_QERAPP_CREATEBRUSHHANDLE)(); -typedef void (WINAPI * PFN_QERAPP_DELETEBRUSHHANDLE)(void* pv); -typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOMAP)(void* pv); -typedef void (WINAPI * PFN_QERAPP_ADDFACE)(void* pv, vec3_t v1, vec3_t v2, vec3_t v3); - -typedef void (WINAPI * PFN_QERAPP_ADDFACEDATA)(void* pv, _QERFaceData *pData); -typedef int (WINAPI * PFN_QERAPP_GETFACECOUNT)(void* pv); -typedef _QERFaceData* (WINAPI * PFN_QERAPP_GETFACEDATA)(void* pv, int nFaceIndex); -typedef void (WINAPI * PFN_QERAPP_SETFACEDATA)(void* pv, int nFaceIndex, _QERFaceData *pData); -typedef void (WINAPI * PFN_QERAPP_DELETEFACE)(void* pv, int nFaceIndex); -typedef void (WINAPI * PFN_QERAPP_TEXTUREBRUSH)(void* pv, char* pName); -typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_SELECTBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_DESELECTBRUSH)(void* pv); // PGM -typedef void (WINAPI * PFN_QERAPP_DESELECTALLBRUSHES)(); // PGM - -typedef void (WINAPI * PFN_QERAPP_DELETESELECTION)(); -typedef void (WINAPI * PFN_QERAPP_GETPOINTS)(int nMax, _QERPointData *pData, char* pMsg); - -typedef int (WINAPI * PFN_QERAPP_SELECTEDBRUSHCOUNT)(); -typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES)(); -typedef void (WINAPI * PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETSELECTEDBRUSHHANDLE)(int nIndex); - -typedef int (WINAPI * PFN_QERAPP_ACTIVEBRUSHCOUNT)(); -typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES)(); -typedef void (WINAPI * PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETACTIVEBRUSHHANDLE)(int nIndex); - -typedef int (WINAPI * PFN_QERAPP_TEXTURECOUNT)(); -typedef char* (WINAPI * PFN_QERAPP_GETTEXTURE)(int nIndex); -typedef char* (WINAPI * PFN_QERAPP_GETCURRENTTEXTURE)(); -typedef void (WINAPI * PFN_QERAPP_SETCURRENTTEXTURE)(char* pName); - -typedef void (WINAPI * PFN_QERAPP_REGISTERMAPLOAD)(void* vp); -typedef void (WINAPI * PFN_QERAPP_REGISTERMAPSAVE)(void* vp); - -typedef int (WINAPI * PFN_QERAPP_GETECLASSCOUNT)(); -typedef char* (WINAPI * PFN_QERAPP_GETECLASS)(int nIndex); - -typedef void (WINAPI * PFN_QERAPP_RESETPLUGINS)(); -//--typedef int (WINAPI* PFN_QERAPP_GETENTITYCOUNT)(); - -/*! -\fn LoadTextureRGBA -\param pPixels is the raw RGBA pixel data (24bits, 8 bit depth) -\param nWidth image width -\param nHeight image height -this will work from the RGBA data and create a GL texture (accessed through a GL bind number) -it takes care of creating the mipmapping levels too -see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=575 for some related issues -*/ -typedef qtexture_t* (* PFN_QERAPP_LOADTEXTURERGBA)(unsigned char* pPixels, int nWidth, int nHeight); - -//--typedef LPCSTR (WINAPI* PFN_QERAPP_GETENTITY)(int nIndex); - -// v1.70 -typedef int (WINAPI * PFN_QERAPP_GETENTITYCOUNT)(); -typedef void* (WINAPI * PFN_QERAPP_GETENTITYHANDLE)(int nIndex); -// FIXME: those two are fairly outdated, you get the epairs -// but you don't have a clean epair read/write query -// and you rely on the C structs directly, which might go away soon -// ok now, stop using, it's bad for your karma (see iepairs.h instead) -typedef epair_t* (WINAPI * PFN_QERAPP_ALLOCATEEPAIR)( char*, char* ); -typedef int (WINAPI * PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES)(void* vp); -typedef void (WINAPI * PFN_QERAPP_RELEASEENTITYBRUSHHANDLES)(); -typedef void* (WINAPI * PFN_QERAPP_GETENTITYBRUSHHANDLE)(int nIndex); -typedef void* (WINAPI * PFN_QERAPP_CREATEENTITYHANDLE)(); -typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOENTITY)( void* vpBrush, void* vpEntity); -typedef void (WINAPI * PFN_QERAPP_COMMITENTITYHANDLETOMAP)(void* vp); -typedef void (WINAPI * PFN_QERAPP_SETSCREENUPDATE)(int bScreenUpdate); -// this one uses window flags defined in qertypes.h -typedef void (WINAPI * PFN_QERAPP_SYSUPDATEWINDOWS)(int bits); -//++timo remove this one -typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH2)(void* vp, int bConvert); - -// v1.80 -typedef void (WINAPI * PFN_QERAPP_GETDISPATCHPARAMS)(vec3_t vMin, vec3_t vMax, bool *bSingleBrush); - -typedef int (WINAPI * PFN_QERAPP_REQUESTINTERFACE)( REFGUID, void* ); -// use this one for errors, Radiant will stop after the "edit preferences" dialog -typedef void (WINAPI * PFN_QERAPP_ERROR)(char* pMsg, ...); -// use to gain read access to the project epairs -// FIXME: removed, accessed through QERPlug_RegisterPluginEntities with the IEpair interface -// typedef void (WINAPI* PFN_QERAPP_GETPROJECTEPAIR)(epair_t **); -// used to allocate and read a buffer -//++timo NOTE: perhaps this would need moving to some kind of dedicated interface -typedef int (WINAPI * PFN_QERAPP_LOADFILE)(const char *pLocation, void ** buffer); -typedef char* (WINAPI * PFN_QERAPP_EXPANDRELETIVEPATH)(char *); -typedef void (WINAPI * PFN_QERAPP_QECONVERTDOSTOUNIXNAME)( char *dst, const char *src ); -typedef int (WINAPI * PFN_QERAPP_HASSHADER)(const char *); -typedef int (WINAPI * PFN_QERAPP_TEXTURELOADSKIN)(char *pName, int *pnWidth, int *pnHeight); -// retrieves the path to the engine from the preferences dialog box -typedef const char* (WINAPI * PFN_QERAPP_GETGAMEPATH)(); -// retrieves full Radiant path -typedef const char* (WINAPI * PFN_QERAPP_GETQERPATH)(); -// retieves .game name of current active game -typedef const char* (WINAPI * PFN_QERAPP_GETGAMEFILE)(); - -// patches in/out -// NOTE: this is a bit different from the brushes in/out, no LPVOID handles this time -// use int indexes instead -// if you call AllocateActivePatchHandles, you'll be playing with active patches -// AllocateSelectedPatcheHandles for selected stuff -// a call to CreatePatchHandle will move you to a seperate index table -typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES) (); -typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES) (); -typedef void (WINAPI * PFN_QERAPP_RELEASEPATCHHANDLES) (); -typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHDATA) (int); -typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHHANDLE) (int); -typedef void (WINAPI * PFN_QERAPP_DELETEPATCH) (int); -typedef int (WINAPI * PFN_QERAPP_CREATEPATCHHANDLE) (); -// when commiting, only a few patchMesh_t members are relevant: -// int width, height; // in control points, not patches -// int contents, flags, value, type; -// drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; -// once you have commited the index is still available, if the patch handle was allocated by you -// then you can re-use the index to commit other patches .. otherwise you can change existing patches -// NOTE: the handle thing for plugin-allocated patches is a bit silly (nobody's perfect) -// TODO: change current behaviour to an index = 0 to tell Radiant to allocate, other indexes to existing patches -// patch is selected after a commit -// you can add an optional texture / shader name .. if NULL will use the current texture -typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOMAP) (int, patchMesh_t* pMesh, char *texName); -typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOENTITY) (int, patchMesh_t* pMesh, char *texName, void* vpEntity); - -// console output -#define SYS_VRB 0 ///< verbose support (on/off) -#define SYS_STD 1 ///< standard print level - this is the default -#define SYS_WRN 2 ///< warnings -#define SYS_ERR 3 ///< error -#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) -typedef void (WINAPI* PFN_QERAPP_SYSPRINTF) (const char *text, ...); -typedef void (WINAPI* PFN_QERAPP_SYSFPRINTF) (int flag, const char *text, ...); - -typedef void (WINAPI* PFN_QERAPP_SYSBEGINWAIT) (); -typedef void (WINAPI* PFN_QERAPP_SYSENDWAIT) (); - -typedef void (* PFN_QERAPP_SYSBEEP) (); - -typedef void (* PFN_QERAPP_SYSSTATUS) (const char *psz, int part ); - -// core map functionality -typedef void (* PFN_QERAPP_MAPNEW) (); -typedef void (* PFN_QERAPP_MAPFREE) (); -typedef void (* PFN_QERAPP_MAPBUILDBRUSHDATA) (); -typedef qboolean (* PFN_QERAPP_MAPISBRUSHFILTERED) (brush_t *); -typedef void (* PFN_QERAPP_MAPSTARTPOSITION) (); -typedef void (* PFN_QERAPP_MAPREGIONOFF) (); -//typedef void (* PFN_QERAPP_SAVEASDIALOG) (bool bRegion); -typedef void (* PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD) (bool); -typedef void (* PFN_QERAPP_POINTFILECLEAR) (); - -typedef void (* PFN_QERAPP_SYSSETTITLE) (const char *text); - -typedef void (* PFN_QERAPP_CSGMAKEHOLLOW) (); - -typedef void (* PFN_QERAPP_REGIONSPAWNPOINT) (FILE *f); - -/*! -access to a portable GetTickCount -*/ -typedef unsigned long (* PFN_QERAPP_GETTICKCOUNT) (); - -class IModelCache -{ -public: - virtual entity_interfaces_t *GetByID(const char *id, const char* version) = 0; - virtual void DeleteByID(const char *id, const char* version) = 0; - virtual void RefreshAll() = 0; -}; - -typedef IModelCache* (* PFN_GETMODELCACHE)(); - -class IFileTypeList -{ -public: - virtual void addType(filetype_t type) = 0; -}; - -class IFileTypeRegistry -{ -public: - virtual void addType(const char* key, filetype_t type) = 0; - virtual void getTypeList(const char* key, IFileTypeList* typelist) = 0; -private: -}; - -typedef IFileTypeRegistry* (* PFN_GETFILETYPEREGISTRY)(); - -typedef const char* (* PFN_QERAPP_READPROJECTKEY)(const char* key); - -typedef char* (* PFN_GETMAPFILENAME)(); - - // FIXME: -// add map format extensions -// add texture format handlers -// add surface dialog handler -// add model handler/displayer - -// v1 func table -// Plugins need to declare one of these and implement the getfunctable as described above -struct _QERFuncTable_1 -{ - int m_nSize; - PFN_QERAPP_CREATEBRUSH m_pfnCreateBrush; - PFN_QERAPP_CREATEBRUSHHANDLE m_pfnCreateBrushHandle; - PFN_QERAPP_DELETEBRUSHHANDLE m_pfnDeleteBrushHandle; - PFN_QERAPP_COMMITBRUSHHANDLETOMAP m_pfnCommitBrushHandle; - PFN_QERAPP_ADDFACE m_pfnAddFace; - PFN_QERAPP_ADDFACEDATA m_pfnAddFaceData; - PFN_QERAPP_GETFACEDATA m_pfnGetFaceData; - PFN_QERAPP_GETFACECOUNT m_pfnGetFaceCount; - PFN_QERAPP_SETFACEDATA m_pfnSetFaceData; - PFN_QERAPP_DELETEFACE m_pfnDeleteFace; - PFN_QERAPP_TEXTUREBRUSH m_pfnTextureBrush; - PFN_QERAPP_BUILDBRUSH m_pfnBuildBrush; // PGM - PFN_QERAPP_SELECTBRUSH m_pfnSelectBrush; // PGM - PFN_QERAPP_DESELECTBRUSH m_pfnDeselectBrush; // PGM - PFN_QERAPP_DESELECTALLBRUSHES m_pfnDeselectAllBrushes; // PGM - - PFN_QERAPP_DELETESELECTION m_pfnDeleteSelection; - PFN_QERAPP_GETPOINTS m_pfnGetPoints; - - PFN_QERAPP_SELECTEDBRUSHCOUNT m_pfnSelectedBrushCount; - PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES m_pfnAllocateSelectedBrushHandles; - PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES m_pfnReleaseSelectedBrushHandles; - PFN_QERAPP_GETSELECTEDBRUSHHANDLE m_pfnGetSelectedBrushHandle; - - PFN_QERAPP_ACTIVEBRUSHCOUNT m_pfnActiveBrushCount; - PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES m_pfnAllocateActiveBrushHandles; - PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES m_pfnReleaseActiveBrushHandles; - PFN_QERAPP_GETACTIVEBRUSHHANDLE m_pfnGetActiveBrushHandle; - - //++timo this would need to be removed and replaced by the IShaders interface - PFN_QERAPP_TEXTURECOUNT m_pfnTextureCount; - PFN_QERAPP_GETTEXTURE m_pfnGetTexture; - PFN_QERAPP_GETCURRENTTEXTURE m_pfnGetCurrentTexture; - PFN_QERAPP_SETCURRENTTEXTURE m_pfnSetCurrentTexture; - - PFN_QERAPP_GETECLASSCOUNT m_pfnGetEClassCount; - PFN_QERAPP_GETECLASS m_pfnGetEClass; - PFN_QERAPP_RESETPLUGINS m_pfnResetPlugins; - // v1.00 ends here - // v1.50 starts here - PFN_QERAPP_LOADTEXTURERGBA m_pfnLoadTextureRGBA; - // v1.50 ends here - // v1.70 starts here - PFN_QERAPP_GETENTITYCOUNT m_pfnGetEntityCount; - PFN_QERAPP_GETENTITYHANDLE m_pfnGetEntityHandle; - PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES m_pfnAllocateEntityBrushHandles; - PFN_QERAPP_RELEASEENTITYBRUSHHANDLES m_pfnReleaseEntityBrushHandles; - PFN_QERAPP_GETENTITYBRUSHHANDLE m_pfnGetEntityBrushHandle; - PFN_QERAPP_CREATEENTITYHANDLE m_pfnCreateEntityHandle; - PFN_QERAPP_COMMITBRUSHHANDLETOENTITY m_pfnCommitBrushHandleToEntity; - PFN_QERAPP_COMMITENTITYHANDLETOMAP m_pfnCommitEntityHandleToMap; - PFN_QERAPP_ALLOCATEEPAIR m_pfnAllocateEpair; - PFN_QERAPP_SETSCREENUPDATE m_pfnSetScreenUpdate; - PFN_QERAPP_BUILDBRUSH2 m_pfnBuildBrush2; - // v1.70 ends here - // v1.80 starts here - PFN_QERAPP_GETDISPATCHPARAMS m_pfnGetDispatchParams; - - // plugins can request additional interfaces - PFN_QERAPP_REQUESTINTERFACE m_pfnRequestInterface; - PFN_QERAPP_ERROR m_pfnError; - // loading a file into a buffer - PFN_QERAPP_LOADFILE m_pfnLoadFile; - PFN_QERAPP_EXPANDRELETIVEPATH m_pfnExpandReletivePath; - PFN_QERAPP_QECONVERTDOSTOUNIXNAME m_pfnQE_ConvertDOSToUnixName; - PFN_QERAPP_HASSHADER m_pfnHasShader; - PFN_QERAPP_TEXTURELOADSKIN m_pfnTexture_LoadSkin; - PFN_QERAPP_GETGAMEPATH m_pfnGetGamePath; - PFN_QERAPP_GETQERPATH m_pfnGetQERPath; - PFN_QERAPP_GETGAMEFILE m_pfnGetGameFile; - // patches in / out - PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES m_pfnAllocateActivePatchHandles; - PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES m_pfnAllocateSelectedPatchHandles; - PFN_QERAPP_RELEASEPATCHHANDLES m_pfnReleasePatchHandles; - PFN_QERAPP_GETPATCHDATA m_pfnGetPatchData; - PFN_QERAPP_GETPATCHHANDLE m_pfnGetPatchHandle; - PFN_QERAPP_DELETEPATCH m_pfnDeletePatch; - PFN_QERAPP_CREATEPATCHHANDLE m_pfnCreatePatchHandle; - PFN_QERAPP_COMMITPATCHHANDLETOMAP m_pfnCommitPatchHandleToMap; - PFN_QERAPP_COMMITPATCHHANDLETOENTITY m_pfnCommitPatchHandleToEntity; - - PFN_QERAPP_LOADIMAGE m_pfnLoadImage; - - // GTK+ functions - PFN_QERAPP_MESSAGEBOX m_pfnMessageBox; - PFN_QERAPP_FILEDIALOG m_pfnFileDialog; - PFN_QERAPP_DIRDIALOG m_pfnDirDialog; - PFN_QERAPP_COLORDIALOG m_pfnColorDialog; - PFN_QERAPP_LOADBITMAP m_pfnLoadBitmap; - - // Profile functions - PFN_QERAPP_PROFILE_GETDIR m_pfnProfileGetDirectory; - PFN_QERAPP_PROFILE_SAVEINT m_pfnProfileSaveInt; - PFN_QERAPP_PROFILE_SAVESTR m_pfnProfileSaveString; - PFN_QERAPP_PROFILE_LOADINT m_pfnProfileLoadInt; - PFN_QERAPP_PROFILE_LOADSTR m_pfnProfileLoadString; - - // Sys_ functions - PFN_QERAPP_SYSUPDATEWINDOWS m_pfnSysUpdateWindows; - PFN_QERAPP_SYSBEEP m_pfnSysBeep; - PFN_QERAPP_SYSPRINTF m_pfnSysPrintf; - PFN_QERAPP_SYSFPRINTF m_pfnSysFPrintf; - PFN_QERAPP_SYSBEGINWAIT m_pfnSysBeginWait; - PFN_QERAPP_SYSENDWAIT m_pfnSysEndWait; - PFN_QERAPP_SYSSETTITLE m_pfnSys_SetTitle; - PFN_QERAPP_SYSSTATUS m_pfnSys_Status; - - // some core functionality on the map - PFN_QERAPP_MAPNEW m_pfnMapNew; - PFN_QERAPP_MAPFREE m_pfnMapFree; - PFN_QERAPP_MAPBUILDBRUSHDATA m_pfnMapBuildBrushData; - PFN_QERAPP_MAPISBRUSHFILTERED m_pfnMap_IsBrushFiltered; - PFN_QERAPP_MAPSTARTPOSITION m_pfnMapStartPosition; - PFN_QERAPP_MAPREGIONOFF m_pfnMapRegionOff; - PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD m_pfnSetBuildWindingsNoTexBuild; -// PFN_QERAPP_SAVEASDIALOG m_pfnSaveAsDialog; - PFN_QERAPP_POINTFILECLEAR m_pfnPointFileClear; - - // FIXME TTimo prolly want to move that somewhere else - PFN_QERAPP_CSGMAKEHOLLOW m_pfnCSG_MakeHollow; - - PFN_QERAPP_REGIONSPAWNPOINT m_pfnRegionSpawnPoint; - PFN_QERAPP_GETTICKCOUNT m_pfnQGetTickCount; - PFN_GETMODELCACHE m_pfnGetModelCache; - PFN_GETFILETYPEREGISTRY m_pfnGetFileTypeRegistry; - - PFN_QERAPP_READPROJECTKEY m_pfnReadProjectKey; - - // digibob from the old _QERAppBSPFrontendTable table - PFN_GETMAPFILENAME m_pfnGetMapName; -}; - -// macros to access those faster in plugins -#ifdef USE_QERTABLE_DEFINE -#ifndef __QERTABLENAME -#define __QERTABLENAME g_FuncTable -#endif -#define CSG_MakeHollow __QERTABLENAME.m_pfnCSG_MakeHollow -#define Sys_Beep __QERTABLENAME.m_pfnSysBeep -#define Sys_Printf __QERTABLENAME.m_pfnSysPrintf -#define Sys_FPrintf __QERTABLENAME.m_pfnSysFPrintf -#define Sys_BeginWait __QERTABLENAME.m_pfnSysBeginWait -#define Sys_EndWait __QERTABLENAME.m_pfnSysEndWait -#define Sys_UpdateWindows __QERTABLENAME.m_pfnSysUpdateWindows -#define Sys_SetTitle __QERTABLENAME.m_pfnSys_SetTitle -#define Sys_Status __QERTABLENAME.m_pfnSys_Status -#define Select_Deselect __QERTABLENAME.m_pfnDeselectAllBrushes -#define Map_New __QERTABLENAME.m_pfnMapNew -#define Map_Free __QERTABLENAME.m_pfnMapFree -#define Map_IsBrushFiltered __QERTABLENAME.m_pfnMap_IsBrushFiltered -#define Map_BuildBrushData __QERTABLENAME.m_pfnMapBuildBrushData -#define Map_StartPosition __QERTABLENAME.m_pfnMapStartPosition -#define Map_RegionOff __QERTABLENAME.m_pfnMapRegionOff -#define QE_ConvertDOSToUnixName __QERTABLENAME.m_pfnQE_ConvertDOSToUnixName -#define SetBuildWindingsNoTexBuild __QERTABLENAME.m_pfnSetBuildWindingsNoTexBuild -//#define SaveAsDialog __QERTABLENAME.m_pfnSaveAsDialog -#define Pointfile_Clear __QERTABLENAME.m_pfnPointFileClear -#define SetScreenUpdate __QERTABLENAME.m_pfnSetScreenUpdate -#define Region_SpawnPoint __QERTABLENAME.m_pfnRegionSpawnPoint -#define QGetTickCount __QERTABLENAME.m_pfnGetTickCount -#define GetModelCache __QERTABLENAME.m_pfnGetModelCache -#define GetFileTypeRegistry __QERTABLENAME.m_pfnGetFileTypeRegistry -#else -IFileTypeRegistry* GetFileTypeRegistry(); -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 PlugIns +// +// + +#ifndef __QERPLUGIN_H__ +#define __QERPLUGIN_H__ + +/*! +\todo this header is intended to be turned into a header for the core editor functionality +some portability related code should be moved to synapse (such as the GUID stuff) +*/ + +#include <stdio.h> +#include <string.h> +// TTimo +// ideally the plugin API would be UI toolkit independent, but removing the dependency with GLib seems tricky right now.. +#include <glib.h> +#include "qertypes.h" + +// FIXME TTimo: +// GUID declaration here should be trashed, it is in synapse.h +#ifdef _WIN32 +#include <wtypes.h> +#endif + +#define QER_MAX_NAMELEN 1024 + +#ifndef _WIN32 +#include "misc_def.h" +#endif + +// the editor will look for plugins in two places, the plugins path +// under the application path, and the path under the basepath as defined +// in the project (.qe4) file. +// +// you can drop any number of new texture, model format DLL's in the standard plugin path +// but only one plugin that overrides map loading/saving, surface dialog, surface flags, etc.. +// should be used at one time.. if multiples are loaded then the last one loaded will be the +// active one +// +// type of services the plugin supplies, pass any combo of these flags +// it is assumed the plugin will have a matching function as defined below +// to correlate to the implied functionality +// + +#define RADIANT_MAJOR "radiant" + +// basics +#define QERPLUG_INIT "QERPlug_Init" +#define QERPLUG_GETNAME "QERPlug_GetName" +#define QERPLUG_GETCOMMANDLIST "QERPlug_GetCommandList" +#define QERPLUG_DISPATCH "QERPlug_Dispatch" +#define QERPLUG_GETFUNCTABLE "QERPlug_GetFuncTable" + +// game stuff +#define QERPLUG_GETTEXTUREINFO "QERPlug_GetTextureInfo" // gets a texture info structure +#define QERPLUG_LOADTEXTURE "QERPlug_LoadTexture" // loads a texture, will return an RGBA structure + // and any surface flags/contents for it +#define QERPLUG_GETSURFACEFLAGS "QERPlug_GetSurfaceFlags" // gets a list of surface/content flag names from a plugin + +struct _QERTextureInfo +{ + char m_TextureExtension[QER_MAX_NAMELEN]; // the extension these textures have + qboolean m_bHiColor; // if textures are NOT high color, the default + // palette (as described inthe qe4 file will be used for gamma correction) + // if they are high color, gamma and shading are computed on the fly + // based on the rgba data + //--bool m_bIsShader; // will probably do q3 shaders this way when i merge + qboolean m_bWadStyle; // if this is true, the plugin will be presented with the texture path + // defined in the .qe4 file and is expected to preload all the textures + qboolean m_bHalfLife; // causes brushes to be saved/parsed without the surface contents/flags/value +}; + +struct _QERTextureLoad // returned by a plugin +{ + _QERTextureLoad() + { + memset(reinterpret_cast<void*>(this), 0, sizeof(_QERTextureLoad)); + }; + + ~_QERTextureLoad() + { + delete []m_pRGBA; + delete []m_pName; + }; + + void makeSpace(int nSize) + { + m_pRGBA = new unsigned char[nSize+1]; + }; + + void setName(const char* p) + { + m_pName = new char[strlen(p)+1]; + strcpy(m_pName, p); + }; + + + unsigned char *m_pRGBA; // rgba data (alpha channel is supported and drawn appropriately) + int m_nWidth; // width + int m_nHeight; // height + int m_nContents; // default contents + int m_nFlags; // "" flags + int m_nValue; // "" value + char *m_pName; // name to be referenced in map, build tools, etc. +}; + +struct _QERModelInfo +{ + char m_ModelExtension[QER_MAX_NAMELEN]; + bool m_bSkinned; + bool m_bMultipart; +}; + +struct _QERModelLoad +{ + // vertex and skin data +}; + + +//========================================= +// plugin functions +#if 0 +// NOTE TTimo: hack to make old plugin tech and new plugin tech live together +#ifndef _IPLUGIN_H_ +// toolkit-independant interface, cast hwndMain to GtkWidget* +typedef const char* (WINAPI *PFN_QERPLUG_INIT)(void* hApp, void* hwndMain); +typedef const char* (WINAPI *PFN_QERPLUG_GETNAME)(); +typedef const char* (WINAPI *PFN_QERPLUG_GETCOMMANDLIST)(); +typedef void (WINAPI *PFN_QERPLUG_DISPATCH)(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush); +#endif +#endif + +typedef char* (WINAPI *PFN_QERPLUG_GETFUNCTABLE)(); + +// v1.5 +// +// Texture loading +// returns a ptr to _QERTextureInfo +typedef void* (WINAPI *PFN_QERPLUG_GETTEXTUREINFO)(); +// +// loads a texture by calling the texture load func in the editor (defined below) +// transparency (for water, fog, lava, etc.. ) can be emulated in the editor +// by passing in appropriate alpha data or by setting the appropriate surface flags +// expected by q2 (which the editor will use.. ) +typedef void (WINAPI *PFN_QERPLUG_LOADTEXTURE)(const char* pFilename); + +// v1.6 +typedef void* (WINAPI *PFN_QERPLUG_GETSURFACEFLAGS)(); + +// v1.7 +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can register the EClasses he wants to handle +//++timo TODO: this has got to move into the table, and be requested by QERPlug_RequestInterface +//++timo FIXME: the LPVOID parameter must be casted to an IEpair interface +#define QERPLUG_REGISTERPLUGINENTITIES "QERPlug_RegisterPluginEntities" +typedef void (WINAPI * PFN_QERPLUG_REGISTERPLUGINENTITIES)( void* ); + +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can Init all it needs for surface properties +#define QERPLUG_INITSURFACEPROPERTIES "QERPlug_InitSurfaceProperties" +typedef void (WINAPI * PFN_QERPLUG_INITSURFACEPROPERTIES)(); + +// if Radiant needs to use a particular set of commands, it can request the plugin to fill a func table +// this is similar to PFN_QERAPP_REQUESTINTERFACE +#define QERPLUG_REQUESTINTERFACE "QERPlug_RequestInterface" +typedef int (WINAPI * PFN_QERPLUG_REQUESTINTERFACE) (REFGUID refGUID, void* pInterface, const char *version_name); + +// Load an image file +typedef void (* PFN_QERAPP_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +// TTimo FIXME: the logic for this is in synapse now + +// MODULES specific: +// if it exports this entry point, will be considered as a module +// a module is a plugin that provides some REQUIRED interfaces to Radiant, such as the shader module +// Radiant will call QERPLUG_LISTINTERFACES to get a list of the interfaces a given plugin implements +// then it will call PFN_QERPLUG_REQUESTINTERFACE to actually get them + +// following leo's code .. looks ok to use a string to identify the various versions of a same interface +// obviously it would be handy to have the same string naming for the interfaces. +// best way would be to have the names come in when you list the interfaces +// NOTE: we might have a problem with the order in which the interfaces are filled in +// there's some kind of dependency graph, the shader module expects to find the VFS ready etc. +typedef struct moduleentry_s { + const GUID *interface_GUID; + const char* interface_name; + const char* version_name; +} moduleentry_t; + +#define QERPLUG_LISTINTERFACES "QERPlug_ListInterfaces" +#define MAX_QERPLUG_INTERFACES 10 +typedef int (WINAPI* PFN_QERPLUG_LISTINTERFACES) (moduleentry_t table[MAX_QERPLUG_INTERFACES]); + +// ======================================== +// GTK+ helper functions + +// NOTE: parent can be NULL in all functions but it's best to set them + +// simple Message Box, see above for the 'type' flags +// toolkit-independent, cast parent ot a GtkWidget* +typedef gint (WINAPI* PFN_QERAPP_MESSAGEBOX) (void *parent, const char* text, + const char* caption, guint32 type, const char *URL); + +// file and directory selection functions return NULL if the user hits cancel +// or a gchar* string that must be g_free'd by the user +// - 'title' is the dialog title (can be NULL) +// - 'path' is used to set the initial directory (can be NULL) +// - 'pattern': the first pattern is for the win32 mode, then comes the Gtk pattern list, see Radiant source for samples +// TTimo 04/01/2001 toolkit-independant, cast parent to a GtkWidget* +typedef const gchar* (* PFN_QERAPP_FILEDIALOG) (void *parent, gboolean open, const char* title, + const char* path, const char* pattern); +typedef gchar* (WINAPI* PFN_QERAPP_DIRDIALOG) (void *parent, const char* title, + const char* path); + +// return true if the user closed the dialog with 'Ok' +// 'color' is used to set the initial value and store the selected value +typedef bool (WINAPI* PFN_QERAPP_COLORDIALOG) (void *parent, float *color, + const char* title); + +// load a .bmp file and store the results in 'gdkpixmap' and 'mask' +// returns TRUE on success but even if it fails, it creates an empty pixmap +// NOTE: 'filename' is relative to <radiant_path>/plugins/bitmaps/ +// TTimo 04/01/2001 toolkit-independant, cast gkpixmap to GdkPixmap and mask to GdkBitmap +typedef bool (WINAPI* PFN_QERAPP_LOADBITMAP) (const char* filename, void **gdkpixmap, void **mask); + +// ======================================== +// read/write preferences file + +// use this function to get the directory where the preferences file are stored +typedef const char* (WINAPI* PFN_QERAPP_PROFILE_GETDIR) (); + +// 'filename' is the absolute path +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVEINT) (const char *filename, const char *section, + const char *key, int value); +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVESTR) (const char *filename, const char *section, + const char *key, const char *value); +typedef int (WINAPI* PFN_QERAPP_PROFILE_LOADINT) (const char *filename, const char *section, + const char *key, int default_value); +typedef char* (WINAPI* PFN_QERAPP_PROFILE_LOADSTR) (const char *filename, const char *section, + const char *key, const char *default_value); + +//========================================= +// editor functions + +// There are 3 potential brush handle lists +// 1. the list that contains brushes a plugin creates using CreateBrushHandle +// 2. the selected brush list (brushes the user has selected) +// 3. the active brush list (brushes in the map that are not selected) +// +// In general, the same things can be done to brush handles (face manip, delete brushhandle, etc.. ) in each +// list. There are a few exceptions. +// 1. You cannot commit a selected or active brush handle to the map. This is because it is already in the map. +// 2. You cannot bind brush handles from the selected or active brush list to an entity. As of v1.0 of the plugins +// the only way for a plugin to create entities is to create a brush handles (or a list of handles) and then bind +// them to an entity. This will commit the brush(s) and/or the entities to the map as well. +// +// To use the active or selected brush lists, you must first allocate them (which returns a count) and then +// release them when you are finish manipulating brushes in one of those lists. + +//++timo NOTE : the #defines here are never used, but can help finding where things are done in the editor +#if 0 +// brush manipulation routines +#define QERAPP_CREATEBRUSH "QERApp_CreateBrush" +#define QERAPP_CREATEBRUSHHANDLE "QERApp_CreateBrushHandle" +#define QERAPP_DELETEBRUSHHANDLE "QERApp_DeleteBrushHandle" +#define QERAPP_COMMITBRUSHHANDLETOMAP "QERApp_CommitBrushHandleToMap" +//++timo not implemented .. remove +// #define QERAPP_BINDHANDLESTOENTITY "QERApp_BindHandlesToEntity" +#define QERAPP_ADDFACE "QERApp_AddFace" +#define QERAPP_ADDFACEDATA "QERApp_AddFaceData" +#define QERAPP_GETFACECOUNT "QERApp_GetFaceCount" +#define QERAPP_GETFACEDATA "QERApp_GetFaceData" +#define QERAPP_SETFACEDATA "QERApp_SetFaceData" +#define QERAPP_DELETEFACE "QERApp_DeleteFace" +#define QERAPP_TEXTUREBRUSH "QERApp_TextureBrush" +#define QERAPP_BUILDBRUSH "QERApp_BuildBrush" // PGM +#define QERAPP_SELECTEDBRUSHCOUNT "QERApp_SelectedBrushCount" +#define QERAPP_ALLOCATESELECTEDBRUSHHANDLES "QERApp_AllocateSelectedBrushHandles" +#define QERAPP_RELEASESELECTEDBRUSHHANDLES "QERApp_ReleaseSelectedBrushHandles" +#define QERAPP_GETSELECTEDBRUSHHANDLE "QERApp_GetSelectedBrushHandle" +#define QERAPP_ACTIVEBRUSHCOUNT "QERApp_ActiveBrushCount" +#define QERAPP_ALLOCATEACTIVEBRUSHHANDLES "QERApp_AllocateActiveBrushHandles" +#define QERAPP_RELEASEACTIVEBRUSHHANDLES "QERApp_ReleaseActiveBrushHandles" +#define QERAPP_GETACTIVEBRUSHHANDLE "QERApp_GetActiveBrushHandle" + +// texture stuff +#define QERAPP_TEXTURECOUNT "QERApp_TextureCount" +#define QERAPP_GETTEXTURE "QERApp_GetTexture" +#define QERAPP_GETCURRENTTEXTURE "QERApp_GetCurrentTexture" +#define QERAPP_SETCURRENTTEXTURE "QERApp_SetCurrentTexture" + +// selection +#define QERAPP_DELETESELECTION "QERApp_DeleteSelection" +#define QERAPP_SELECTBRUSH "QERApp_SelectBrush" // PGM +#define QERAPP_DESELECTBRUSH "QERApp_DeselectBrush" // PGM +#define QERAPP_DESELECTALLBRUSHES "QERApp_DeselectAllBrushes" // PGM + +// data gathering +#define QERAPP_GETPOINTS "QERApp_GetPoints" +#define QERAPP_SELECTBRUSHES "QERApp_GetBrushes" + +// entity class stuff +// the entity handling is very basic for 1.0 +#define QERAPP_GETECLASSCOUNT "QERApp_GetEClassCount" +#define QERAPP_GETECLASS "QERApp_GetEClass" + +// misc +#define QERAPP_SYSMSG "QERApp_SysMsg" +#define QERAPP_INFOMSG "QERApp_InfoMsg" +#define QERAPP_HIDEINFOMSG "QERApp_HideInfoMsg" +#define QERAPP_RESET_PLUGINS "QERApp_ResetPlugins" + +// texture loading +#define QERAPP_LOADTEXTURERGBA "QERApp_LoadTextureRGBA" + +// FIXME: the following are not implemented yet +// hook registrations +#define QERAPP_REGISTER_MAPLOADFUNC "QERApp_Register_MapLoadFunc" +#define QERAPP_REGISTER_MAPSAVEFUNC "QERApp_Register_MapSaveFunc" + +// FIXME: the following are not implemented yet +#define QERAPP_REGISTER_PROJECTLOADFUNC "QERApp_Register_ProjectLoadFunc" +#define QERAPP_REGISTER_MOUSEHANDLER "QERApp_Register_MouseHandler" +#define QERAPP_REGISTER_KEYHANDLER "QERApp_Register_KeyHandler" + +// FIXME: new primtives do not work in v1.00 +// primitives are new types of things in the map +// for instance, the Q3 curves could have been done as +// primitives instead of being built in +// it will be a plugins responsibility to hook the map load and save funcs to load +// and/or save any additional data (like new primitives of some type) +// the editor will call each registered renderer during the rendering process to repaint +// any primitives the plugin owns +// each primitive object has a temporary sibling brush that lives in the map +// FIXME: go backwards on this a bit.. orient it more towards the temp brush mode as it will be cleaner +// basically a plugin will hook the map load and save and will add the primitives to the map.. this will +// produce a temporary 'primitive' brush and the appropriate renderer will be called as well as the +// edit handler (for edge drags, sizes, rotates, etc.. ) and the vertex maker will be called when vertex +// mode is attemped on the brush.. there will need to be a GetPrimitiveBounds callback in the edit handler +// so the brush can resize appropriately as needed.. this might be the plugins responsibility to set the +// sibling brushes size.. it will then be the plugins responsibility to hook map save to save the primitives +// as the editor will discard any temp primitive brushes.. (there probably needs to be some kind of sanity check +// here as far as keeping the brushes and the plugin in sync.. i suppose the edit handler can deal with all of that +// crap but it looks like a nice place for a mess) +#define QERAPP_REGISTER_PRIMITIVE "QERApp_Register_Primitive" +#define QERAPP_REGISTER_RENDERER "QERApp_Register_Renderer" +#define QERAPP_REGISTER_EDITHANDLER "QERApp_Register_EditHandler" +#define QERAPP_REGISTER_VERTEXMAKER "QERApp_Register_VertexMaker" +#define QERAPP_ADDPRIMITIVE "QERApp_AddPrimitive" + +// v1.70 +#define QERAPP_GETENTITYCOUNT "QERApp_GetEntityCount" +#define QERAPP_GETENTITYHANDLE "QERApp_GetEntityHandle" +//++timo not implemented for the moment +// #define QERAPP_GETENTITYINFO "QERApp_GetEntityInfo" +//++timo does the keyval need some more funcs to add/remove ? +// get the pointer and do the changes yourself +#define QERAPP_ALLOCATEEPAIR "QERApp_AllocateEpair" +#define QERAPP_ALLOCATEENTITYBRUSHHANDLES "QERApp_AllocateEntityBrushHandles" +#define QERAPP_RELEASEENTITYBRUSHHANDLES "QERApp_ReleaseEntityBrushHandles" +#define QERAPP_GETENTITYBRUSHHANDLE "QERApp_GetEntityBrushHandle" +#define QERAPP_CREATEENTITYHANDLE "QERApp_CreateEntityHandle" +#define QERAPP_COMMITBRUSHHANDLETOENTITY "QERApp_CommitBrushHandleToEntity" +#define QERAPP_COMMITENTITYHANDLETOMAP "QERApp_CommitEntityHandleToMap" +#define QERAPP_SETSCREENUPDATE "QERApp_SetScreenUpdate" +#define QERAPP_BUILDBRUSH2 "QERApp_BuildBrush2" +#endif + +// v1.80 +#define QERAPP_GETDISPATCHPARAMS "QERApp_GetDispatchParams" + +struct _QERPointData +{ + int m_nCount; + vec3_t *m_pVectors; +}; + +struct _QERFaceData +{ + char m_TextureName[QER_MAX_NAMELEN]; + int m_nContents; + int m_nFlags; + int m_nValue; + float m_fShift[2]; + float m_fRotate; + float m_fScale[2]; + vec3_t m_v1, m_v2, m_v3; + // brush primitive additions + qboolean m_bBPrimit; + brushprimit_texdef_t brushprimit_texdef; +}; + +typedef void (WINAPI * PFN_QERAPP_CREATEBRUSH)(vec3_t vMin, vec3_t vMax); + +typedef void* (WINAPI * PFN_QERAPP_CREATEBRUSHHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_DELETEBRUSHHANDLE)(void* pv); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOMAP)(void* pv); +typedef void (WINAPI * PFN_QERAPP_ADDFACE)(void* pv, vec3_t v1, vec3_t v2, vec3_t v3); + +typedef void (WINAPI * PFN_QERAPP_ADDFACEDATA)(void* pv, _QERFaceData *pData); +typedef int (WINAPI * PFN_QERAPP_GETFACECOUNT)(void* pv); +typedef _QERFaceData* (WINAPI * PFN_QERAPP_GETFACEDATA)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_SETFACEDATA)(void* pv, int nFaceIndex, _QERFaceData *pData); +typedef void (WINAPI * PFN_QERAPP_DELETEFACE)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_TEXTUREBRUSH)(void* pv, char* pName); +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_SELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTALLBRUSHES)(); // PGM + +typedef void (WINAPI * PFN_QERAPP_DELETESELECTION)(); +typedef void (WINAPI * PFN_QERAPP_GETPOINTS)(int nMax, _QERPointData *pData, char* pMsg); + +typedef int (WINAPI * PFN_QERAPP_SELECTEDBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETSELECTEDBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_ACTIVEBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETACTIVEBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_TEXTURECOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETTEXTURE)(int nIndex); +typedef char* (WINAPI * PFN_QERAPP_GETCURRENTTEXTURE)(); +typedef void (WINAPI * PFN_QERAPP_SETCURRENTTEXTURE)(char* pName); + +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPLOAD)(void* vp); +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPSAVE)(void* vp); + +typedef int (WINAPI * PFN_QERAPP_GETECLASSCOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETECLASS)(int nIndex); + +typedef void (WINAPI * PFN_QERAPP_RESETPLUGINS)(); +//--typedef int (WINAPI* PFN_QERAPP_GETENTITYCOUNT)(); + +/*! +\fn LoadTextureRGBA +\param pPixels is the raw RGBA pixel data (24bits, 8 bit depth) +\param nWidth image width +\param nHeight image height +this will work from the RGBA data and create a GL texture (accessed through a GL bind number) +it takes care of creating the mipmapping levels too +see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=575 for some related issues +*/ +typedef qtexture_t* (* PFN_QERAPP_LOADTEXTURERGBA)(unsigned char* pPixels, int nWidth, int nHeight); + +//--typedef LPCSTR (WINAPI* PFN_QERAPP_GETENTITY)(int nIndex); + +// v1.70 +typedef int (WINAPI * PFN_QERAPP_GETENTITYCOUNT)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYHANDLE)(int nIndex); +// FIXME: those two are fairly outdated, you get the epairs +// but you don't have a clean epair read/write query +// and you rely on the C structs directly, which might go away soon +// ok now, stop using, it's bad for your karma (see iepairs.h instead) +typedef epair_t* (WINAPI * PFN_QERAPP_ALLOCATEEPAIR)( char*, char* ); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES)(void* vp); +typedef void (WINAPI * PFN_QERAPP_RELEASEENTITYBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYBRUSHHANDLE)(int nIndex); +typedef void* (WINAPI * PFN_QERAPP_CREATEENTITYHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOENTITY)( void* vpBrush, void* vpEntity); +typedef void (WINAPI * PFN_QERAPP_COMMITENTITYHANDLETOMAP)(void* vp); +typedef void (WINAPI * PFN_QERAPP_SETSCREENUPDATE)(int bScreenUpdate); +// this one uses window flags defined in qertypes.h +typedef void (WINAPI * PFN_QERAPP_SYSUPDATEWINDOWS)(int bits); +//++timo remove this one +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH2)(void* vp, int bConvert); + +// v1.80 +typedef void (WINAPI * PFN_QERAPP_GETDISPATCHPARAMS)(vec3_t vMin, vec3_t vMax, bool *bSingleBrush); + +typedef int (WINAPI * PFN_QERAPP_REQUESTINTERFACE)( REFGUID, void* ); +// use this one for errors, Radiant will stop after the "edit preferences" dialog +typedef void (WINAPI * PFN_QERAPP_ERROR)(char* pMsg, ...); +// use to gain read access to the project epairs +// FIXME: removed, accessed through QERPlug_RegisterPluginEntities with the IEpair interface +// typedef void (WINAPI* PFN_QERAPP_GETPROJECTEPAIR)(epair_t **); +// used to allocate and read a buffer +//++timo NOTE: perhaps this would need moving to some kind of dedicated interface +typedef int (WINAPI * PFN_QERAPP_LOADFILE)(const char *pLocation, void ** buffer); +typedef char* (WINAPI * PFN_QERAPP_EXPANDRELETIVEPATH)(char *); +typedef void (WINAPI * PFN_QERAPP_QECONVERTDOSTOUNIXNAME)( char *dst, const char *src ); +typedef int (WINAPI * PFN_QERAPP_HASSHADER)(const char *); +typedef int (WINAPI * PFN_QERAPP_TEXTURELOADSKIN)(char *pName, int *pnWidth, int *pnHeight); +// retrieves the path to the engine from the preferences dialog box +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEPATH)(); +// retrieves full Radiant path +typedef const char* (WINAPI * PFN_QERAPP_GETQERPATH)(); +// retieves .game name of current active game +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEFILE)(); + +// patches in/out +// NOTE: this is a bit different from the brushes in/out, no LPVOID handles this time +// use int indexes instead +// if you call AllocateActivePatchHandles, you'll be playing with active patches +// AllocateSelectedPatcheHandles for selected stuff +// a call to CreatePatchHandle will move you to a seperate index table +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES) (); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES) (); +typedef void (WINAPI * PFN_QERAPP_RELEASEPATCHHANDLES) (); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHDATA) (int); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHHANDLE) (int); +typedef void (WINAPI * PFN_QERAPP_DELETEPATCH) (int); +typedef int (WINAPI * PFN_QERAPP_CREATEPATCHHANDLE) (); +// when commiting, only a few patchMesh_t members are relevant: +// int width, height; // in control points, not patches +// int contents, flags, value, type; +// drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; +// once you have commited the index is still available, if the patch handle was allocated by you +// then you can re-use the index to commit other patches .. otherwise you can change existing patches +// NOTE: the handle thing for plugin-allocated patches is a bit silly (nobody's perfect) +// TODO: change current behaviour to an index = 0 to tell Radiant to allocate, other indexes to existing patches +// patch is selected after a commit +// you can add an optional texture / shader name .. if NULL will use the current texture +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOMAP) (int, patchMesh_t* pMesh, char *texName); +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOENTITY) (int, patchMesh_t* pMesh, char *texName, void* vpEntity); + +// console output +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) +typedef void (WINAPI* PFN_QERAPP_SYSPRINTF) (const char *text, ...); +typedef void (WINAPI* PFN_QERAPP_SYSFPRINTF) (int flag, const char *text, ...); + +typedef void (WINAPI* PFN_QERAPP_SYSBEGINWAIT) (); +typedef void (WINAPI* PFN_QERAPP_SYSENDWAIT) (); + +typedef void (* PFN_QERAPP_SYSBEEP) (); + +typedef void (* PFN_QERAPP_SYSSTATUS) (const char *psz, int part ); + +// core map functionality +typedef void (* PFN_QERAPP_MAPNEW) (); +typedef void (* PFN_QERAPP_MAPFREE) (); +typedef void (* PFN_QERAPP_MAPBUILDBRUSHDATA) (); +typedef qboolean (* PFN_QERAPP_MAPISBRUSHFILTERED) (brush_t *); +typedef void (* PFN_QERAPP_MAPSTARTPOSITION) (); +typedef void (* PFN_QERAPP_MAPREGIONOFF) (); +//typedef void (* PFN_QERAPP_SAVEASDIALOG) (bool bRegion); +typedef void (* PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD) (bool); +typedef void (* PFN_QERAPP_POINTFILECLEAR) (); + +typedef void (* PFN_QERAPP_SYSSETTITLE) (const char *text); + +typedef void (* PFN_QERAPP_CSGMAKEHOLLOW) (); + +typedef void (* PFN_QERAPP_REGIONSPAWNPOINT) (FILE *f); + +/*! +access to a portable GetTickCount +*/ +typedef unsigned long (* PFN_QERAPP_GETTICKCOUNT) (); + +class IModelCache +{ +public: + virtual entity_interfaces_t *GetByID(const char *id, const char* version) = 0; + virtual void DeleteByID(const char *id, const char* version) = 0; + virtual void RefreshAll() = 0; +}; + +typedef IModelCache* (* PFN_GETMODELCACHE)(); + +class IFileTypeList +{ +public: + virtual void addType(filetype_t type) = 0; +}; + +class IFileTypeRegistry +{ +public: + virtual void addType(const char* key, filetype_t type) = 0; + virtual void getTypeList(const char* key, IFileTypeList* typelist) = 0; +private: +}; + +typedef IFileTypeRegistry* (* PFN_GETFILETYPEREGISTRY)(); + +typedef const char* (* PFN_QERAPP_READPROJECTKEY)(const char* key); + +typedef char* (* PFN_GETMAPFILENAME)(); + + // FIXME: +// add map format extensions +// add texture format handlers +// add surface dialog handler +// add model handler/displayer + +// v1 func table +// Plugins need to declare one of these and implement the getfunctable as described above +struct _QERFuncTable_1 +{ + int m_nSize; + PFN_QERAPP_CREATEBRUSH m_pfnCreateBrush; + PFN_QERAPP_CREATEBRUSHHANDLE m_pfnCreateBrushHandle; + PFN_QERAPP_DELETEBRUSHHANDLE m_pfnDeleteBrushHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOMAP m_pfnCommitBrushHandle; + PFN_QERAPP_ADDFACE m_pfnAddFace; + PFN_QERAPP_ADDFACEDATA m_pfnAddFaceData; + PFN_QERAPP_GETFACEDATA m_pfnGetFaceData; + PFN_QERAPP_GETFACECOUNT m_pfnGetFaceCount; + PFN_QERAPP_SETFACEDATA m_pfnSetFaceData; + PFN_QERAPP_DELETEFACE m_pfnDeleteFace; + PFN_QERAPP_TEXTUREBRUSH m_pfnTextureBrush; + PFN_QERAPP_BUILDBRUSH m_pfnBuildBrush; // PGM + PFN_QERAPP_SELECTBRUSH m_pfnSelectBrush; // PGM + PFN_QERAPP_DESELECTBRUSH m_pfnDeselectBrush; // PGM + PFN_QERAPP_DESELECTALLBRUSHES m_pfnDeselectAllBrushes; // PGM + + PFN_QERAPP_DELETESELECTION m_pfnDeleteSelection; + PFN_QERAPP_GETPOINTS m_pfnGetPoints; + + PFN_QERAPP_SELECTEDBRUSHCOUNT m_pfnSelectedBrushCount; + PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES m_pfnAllocateSelectedBrushHandles; + PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES m_pfnReleaseSelectedBrushHandles; + PFN_QERAPP_GETSELECTEDBRUSHHANDLE m_pfnGetSelectedBrushHandle; + + PFN_QERAPP_ACTIVEBRUSHCOUNT m_pfnActiveBrushCount; + PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES m_pfnAllocateActiveBrushHandles; + PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES m_pfnReleaseActiveBrushHandles; + PFN_QERAPP_GETACTIVEBRUSHHANDLE m_pfnGetActiveBrushHandle; + + //++timo this would need to be removed and replaced by the IShaders interface + PFN_QERAPP_TEXTURECOUNT m_pfnTextureCount; + PFN_QERAPP_GETTEXTURE m_pfnGetTexture; + PFN_QERAPP_GETCURRENTTEXTURE m_pfnGetCurrentTexture; + PFN_QERAPP_SETCURRENTTEXTURE m_pfnSetCurrentTexture; + + PFN_QERAPP_GETECLASSCOUNT m_pfnGetEClassCount; + PFN_QERAPP_GETECLASS m_pfnGetEClass; + PFN_QERAPP_RESETPLUGINS m_pfnResetPlugins; + // v1.00 ends here + // v1.50 starts here + PFN_QERAPP_LOADTEXTURERGBA m_pfnLoadTextureRGBA; + // v1.50 ends here + // v1.70 starts here + PFN_QERAPP_GETENTITYCOUNT m_pfnGetEntityCount; + PFN_QERAPP_GETENTITYHANDLE m_pfnGetEntityHandle; + PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES m_pfnAllocateEntityBrushHandles; + PFN_QERAPP_RELEASEENTITYBRUSHHANDLES m_pfnReleaseEntityBrushHandles; + PFN_QERAPP_GETENTITYBRUSHHANDLE m_pfnGetEntityBrushHandle; + PFN_QERAPP_CREATEENTITYHANDLE m_pfnCreateEntityHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOENTITY m_pfnCommitBrushHandleToEntity; + PFN_QERAPP_COMMITENTITYHANDLETOMAP m_pfnCommitEntityHandleToMap; + PFN_QERAPP_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_QERAPP_SETSCREENUPDATE m_pfnSetScreenUpdate; + PFN_QERAPP_BUILDBRUSH2 m_pfnBuildBrush2; + // v1.70 ends here + // v1.80 starts here + PFN_QERAPP_GETDISPATCHPARAMS m_pfnGetDispatchParams; + + // plugins can request additional interfaces + PFN_QERAPP_REQUESTINTERFACE m_pfnRequestInterface; + PFN_QERAPP_ERROR m_pfnError; + // loading a file into a buffer + PFN_QERAPP_LOADFILE m_pfnLoadFile; + PFN_QERAPP_EXPANDRELETIVEPATH m_pfnExpandReletivePath; + PFN_QERAPP_QECONVERTDOSTOUNIXNAME m_pfnQE_ConvertDOSToUnixName; + PFN_QERAPP_HASSHADER m_pfnHasShader; + PFN_QERAPP_TEXTURELOADSKIN m_pfnTexture_LoadSkin; + PFN_QERAPP_GETGAMEPATH m_pfnGetGamePath; + PFN_QERAPP_GETQERPATH m_pfnGetQERPath; + PFN_QERAPP_GETGAMEFILE m_pfnGetGameFile; + // patches in / out + PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES m_pfnAllocateActivePatchHandles; + PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES m_pfnAllocateSelectedPatchHandles; + PFN_QERAPP_RELEASEPATCHHANDLES m_pfnReleasePatchHandles; + PFN_QERAPP_GETPATCHDATA m_pfnGetPatchData; + PFN_QERAPP_GETPATCHHANDLE m_pfnGetPatchHandle; + PFN_QERAPP_DELETEPATCH m_pfnDeletePatch; + PFN_QERAPP_CREATEPATCHHANDLE m_pfnCreatePatchHandle; + PFN_QERAPP_COMMITPATCHHANDLETOMAP m_pfnCommitPatchHandleToMap; + PFN_QERAPP_COMMITPATCHHANDLETOENTITY m_pfnCommitPatchHandleToEntity; + + PFN_QERAPP_LOADIMAGE m_pfnLoadImage; + + // GTK+ functions + PFN_QERAPP_MESSAGEBOX m_pfnMessageBox; + PFN_QERAPP_FILEDIALOG m_pfnFileDialog; + PFN_QERAPP_DIRDIALOG m_pfnDirDialog; + PFN_QERAPP_COLORDIALOG m_pfnColorDialog; + PFN_QERAPP_LOADBITMAP m_pfnLoadBitmap; + + // Profile functions + PFN_QERAPP_PROFILE_GETDIR m_pfnProfileGetDirectory; + PFN_QERAPP_PROFILE_SAVEINT m_pfnProfileSaveInt; + PFN_QERAPP_PROFILE_SAVESTR m_pfnProfileSaveString; + PFN_QERAPP_PROFILE_LOADINT m_pfnProfileLoadInt; + PFN_QERAPP_PROFILE_LOADSTR m_pfnProfileLoadString; + + // Sys_ functions + PFN_QERAPP_SYSUPDATEWINDOWS m_pfnSysUpdateWindows; + PFN_QERAPP_SYSBEEP m_pfnSysBeep; + PFN_QERAPP_SYSPRINTF m_pfnSysPrintf; + PFN_QERAPP_SYSFPRINTF m_pfnSysFPrintf; + PFN_QERAPP_SYSBEGINWAIT m_pfnSysBeginWait; + PFN_QERAPP_SYSENDWAIT m_pfnSysEndWait; + PFN_QERAPP_SYSSETTITLE m_pfnSys_SetTitle; + PFN_QERAPP_SYSSTATUS m_pfnSys_Status; + + // some core functionality on the map + PFN_QERAPP_MAPNEW m_pfnMapNew; + PFN_QERAPP_MAPFREE m_pfnMapFree; + PFN_QERAPP_MAPBUILDBRUSHDATA m_pfnMapBuildBrushData; + PFN_QERAPP_MAPISBRUSHFILTERED m_pfnMap_IsBrushFiltered; + PFN_QERAPP_MAPSTARTPOSITION m_pfnMapStartPosition; + PFN_QERAPP_MAPREGIONOFF m_pfnMapRegionOff; + PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD m_pfnSetBuildWindingsNoTexBuild; +// PFN_QERAPP_SAVEASDIALOG m_pfnSaveAsDialog; + PFN_QERAPP_POINTFILECLEAR m_pfnPointFileClear; + + // FIXME TTimo prolly want to move that somewhere else + PFN_QERAPP_CSGMAKEHOLLOW m_pfnCSG_MakeHollow; + + PFN_QERAPP_REGIONSPAWNPOINT m_pfnRegionSpawnPoint; + PFN_QERAPP_GETTICKCOUNT m_pfnQGetTickCount; + PFN_GETMODELCACHE m_pfnGetModelCache; + PFN_GETFILETYPEREGISTRY m_pfnGetFileTypeRegistry; + + PFN_QERAPP_READPROJECTKEY m_pfnReadProjectKey; + + // digibob from the old _QERAppBSPFrontendTable table + PFN_GETMAPFILENAME m_pfnGetMapName; +}; + +// macros to access those faster in plugins +#ifdef USE_QERTABLE_DEFINE +#ifndef __QERTABLENAME +#define __QERTABLENAME g_FuncTable +#endif +#define CSG_MakeHollow __QERTABLENAME.m_pfnCSG_MakeHollow +#define Sys_Beep __QERTABLENAME.m_pfnSysBeep +#define Sys_Printf __QERTABLENAME.m_pfnSysPrintf +#define Sys_FPrintf __QERTABLENAME.m_pfnSysFPrintf +#define Sys_BeginWait __QERTABLENAME.m_pfnSysBeginWait +#define Sys_EndWait __QERTABLENAME.m_pfnSysEndWait +#define Sys_UpdateWindows __QERTABLENAME.m_pfnSysUpdateWindows +#define Sys_SetTitle __QERTABLENAME.m_pfnSys_SetTitle +#define Sys_Status __QERTABLENAME.m_pfnSys_Status +#define Select_Deselect __QERTABLENAME.m_pfnDeselectAllBrushes +#define Map_New __QERTABLENAME.m_pfnMapNew +#define Map_Free __QERTABLENAME.m_pfnMapFree +#define Map_IsBrushFiltered __QERTABLENAME.m_pfnMap_IsBrushFiltered +#define Map_BuildBrushData __QERTABLENAME.m_pfnMapBuildBrushData +#define Map_StartPosition __QERTABLENAME.m_pfnMapStartPosition +#define Map_RegionOff __QERTABLENAME.m_pfnMapRegionOff +#define QE_ConvertDOSToUnixName __QERTABLENAME.m_pfnQE_ConvertDOSToUnixName +#define SetBuildWindingsNoTexBuild __QERTABLENAME.m_pfnSetBuildWindingsNoTexBuild +//#define SaveAsDialog __QERTABLENAME.m_pfnSaveAsDialog +#define Pointfile_Clear __QERTABLENAME.m_pfnPointFileClear +#define SetScreenUpdate __QERTABLENAME.m_pfnSetScreenUpdate +#define Region_SpawnPoint __QERTABLENAME.m_pfnRegionSpawnPoint +#define QGetTickCount __QERTABLENAME.m_pfnGetTickCount +#define GetModelCache __QERTABLENAME.m_pfnGetModelCache +#define GetFileTypeRegistry __QERTABLENAME.m_pfnGetFileTypeRegistry +#else +IFileTypeRegistry* GetFileTypeRegistry(); +#endif + +#endif diff --git a/include/qertypes.h b/include/qertypes.h index 0c6ebbdb..ad785cfe 100644 --- a/include/qertypes.h +++ b/include/qertypes.h @@ -1,911 +1,911 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// qertypes.h -// -// common types -// merged from brush.h, etc. for plugin support -// -#ifndef _QERTYPES_H_ -#define _QERTYPES_H_ - -#ifdef _WIN32 -#include <wtypes.h> -#endif - -#include <GL/gl.h> - -#include "str.h" - -#ifdef _WIN32 -#define PATH_MAX 260 -#endif - -// HACK glib-2.0 -#define NAME_MAX 255 - -typedef bool qboolean; - -#define MAXPOINTS 16 - -// merged from qedefs.h ------ - -#define MAX_EDGES 512 -#define MAX_POINTS 1024 - -#define COLOR_TEXTUREBACK 0 -#define COLOR_GRIDBACK 1 -#define COLOR_GRIDMINOR 2 -#define COLOR_GRIDMAJOR 3 -#define COLOR_CAMERABACK 4 -#define COLOR_ENTITY 5 -#define COLOR_GRIDBLOCK 6 -#define COLOR_GRIDTEXT 7 -#define COLOR_BRUSHES 8 -#define COLOR_SELBRUSHES 9 -#define COLOR_CLIPPER 10 -#define COLOR_VIEWNAME 11 -#define COLOR_SELBRUSHES3D 12 - -#define COLOR_GRIDMINOR_ALT 13 -#define COLOR_GRIDMAJOR_ALT 14 - -#define COLOR_LAST 15 - -// ---------------------------- - -typedef float vec_t; -typedef vec_t vec3_t[3]; - -// turn this on/off to use a static texdef or a memory one -// THIS MUST BE CONSISTENT throughout a whole build of Radiant / modules / plugins -// DO_TEXDEF_ALLOC is more memory efficient, but I suspect it to be wacky on win32 / C runtime etc. -#define DO_TEXDEF_ALLOC 1 -#if DO_TEXDEF_ALLOC - -class texdef_t -{ -private: - char *name; -public: - texdef_t() - { - name = new char[1]; - name[0] = '\0'; - shift[0] = 0.0f; - shift[1] = 0.0f; - rotate = 0.0f; - scale[0] = 1.0f; - scale[1] = 1.0f; - contents = 0; - flags = 0; - value = 0; - } - texdef_t(const texdef_t& other) - { - name = NULL; - SetName(other.name); - shift[0] = other.shift[0]; - shift[1] = other.shift[1]; - rotate = other.rotate; - scale[0] = other.scale[0]; - scale[1] = other.scale[1]; - contents = other.contents; - flags = other.flags; - value = other.value; - } - ~texdef_t() - { - if (name) - { - delete []name; - name = (char*)NULL; - } - } - - void SetName(const char *p) - { - if (name) - { - delete []name; - name = NULL; - } - if (p) - { - name = strcpy(new char[strlen(p)+1], p); - } - else - { - name = new char[1]; - name[0] = '\0'; - } - } - - const char * GetName() const - { - return name; - } - - // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. - void DropName() - { - name = NULL; - SetName(NULL); - } - - texdef_t& operator =(const texdef_t& rhs) - { - if (&rhs != this) - { - SetName(rhs.name); - shift[0] = rhs.shift[0]; - shift[1] = rhs.shift[1]; - rotate = rhs.rotate; - scale[0] = rhs.scale[0]; - scale[1] = rhs.scale[1]; - contents = rhs.contents; - flags = rhs.flags; - value = rhs.value; - } - return *this; - } - float shift[2]; - float rotate; - float scale[2]; - int contents; - int flags; - int value; -}; - -#else - -// max length of a vfs texture path -#define QPATH 64 -class texdef_t -{ -private: - char name[QPATH]; -public: - texdef_t() { name[0] = '\0'; } - ~texdef_t() { } - - void SetName(const char *p) - { - strncpy(name, p, QPATH); - } - - const char * GetName() const - { - return name; - } - - // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. - void DropName() - { - name[0] = '\0'; - } - - texdef_t& operator =(const texdef_t& rhs) - { - if (&rhs != this) - { - SetName(rhs.name); - shift[0] = rhs.shift[0]; - shift[1] = rhs.shift[1]; - rotate = rhs.rotate; - scale[0] = rhs.scale[0]; - scale[1] = rhs.scale[1]; - contents = rhs.contents; - flags = rhs.flags; - value = rhs.value; - } - return *this; - } - float shift[2]; - float rotate; - float scale[2]; - int contents; - int flags; - int value; -}; - -#endif - -// forward declare -class IShader; - -// Timo -// new brush primitive texdef -typedef struct brushprimit_texdef_s -{ - vec_t coords[2][3]; -} brushprimit_texdef_t; - -// this structure is used in Radiant to reflect the state of the texture window -// it gives information on current shader and various flags -class texturewin_t -{ -public: - texturewin_t() - { - } - ~texturewin_t() - { - } - int width, height; - int originy; - // add brushprimit_texdef_t for brush primitive coordinates storage - brushprimit_texdef_t brushprimit_texdef; - int m_nTotalHeight; - // surface plugin, must be casted to a IPluginTexdef* - void* pTexdef; - texdef_t texdef; - // shader - // NOTE: never NULL, initialized in Texture_Init - // NOTE: the reference name of the shader is texdef.name (see QERApp_ReloadShaders for an example) - IShader *pShader; -}; - -#define QER_TRANS 0x00000001 -#define QER_NOCARVE 0x00000002 -#define QER_NODRAW 0x00000004 -#define QER_NONSOLID 0x00000008 -#define QER_WATER 0x00000010 -#define QER_LAVA 0x00000020 -#define QER_FOG 0x00000040 -#define QER_ALPHAFUNC 0x00000080 -#define QER_CULL 0x00000100 - - -// describes a GL texture that Radiant uses to represent a shader -// NOTE: all qtexture_t are stored in a main list at g_qeglobals.d_qtextures -// shaders have reference couting, but qtexture_t don't (they're way too deep into Radiant) -typedef struct qtexture_s -{ - struct qtexture_s *next; - // name of the texture file (the physical image file we are using) - // NOTE: used for lookup, must be unique .. vfs path of the texture, lowercase, NO FILE EXTENSION - // ex textures/gothic_wall/iron - // NOTE: the "textures/" prefix might seem unnecessary .. but it's better to stick to the vfs name - char name[64]; - int width, height; - GLuint texture_number; // gl bind number (the qtexture_t are usually loaded and binded by the shaders module) - vec3_t color; // for flat shade mode - qboolean inuse; // true = is present on the level (for the texture browser interface) -} qtexture_t; - -// NOTE: don't trust this definition! -// you should read float points[..][5] -// see NewWinding definition -// WARNING: don't touch anything to this struct unless you looked into winding.cpp and WINDING_SIZE(pt) -#define MAX_POINTS_ON_WINDING 64 -typedef struct -{ - int numpoints; - int maxpoints; - float points[8][5]; // variable sized -} winding_t; - -typedef struct -{ - vec3_t normal; - double dist; - int type; -} plane_t; - -// pShader is a shortcut to the shader -// it's only up-to-date after a Brush_Build call -// to initialize the pShader, use QERApp_Shader_ForName(texdef.name) -typedef struct face_s -{ - struct face_s *next; - struct face_s *prev; - struct face_s *original; //used for vertex movement - vec3_t planepts[3]; - texdef_t texdef; - plane_t plane; - - // Nurail: Face Undo - int undoId; - int redoId; - - winding_t *face_winding; - - vec3_t d_color; - vec_t d_shade; - // calls through here have indirections (pure virtual) - // it would be good if the rendering loop would avoid scanning there (for the GL binding number for example) - IShader *pShader; - //++timo FIXME: remove! - qtexture_t *d_texture; - - // Timo new brush primit texdef - brushprimit_texdef_t brushprimit_texdef; - - // cast this one to an IPluginTexdef if you are using it - // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h - // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? - void *pData; -} face_t; - -typedef struct { - vec3_t xyz; - float sideST[2]; - float capST[2]; -} curveVertex_t; - -typedef struct { - curveVertex_t v[2]; -} sideVertex_t; - - -#define MIN_PATCH_WIDTH 3 -#define MIN_PATCH_HEIGHT 3 - -#define MAX_PATCH_WIDTH 16 -#define MAX_PATCH_HEIGHT 16 - -// patch type info -// type in lower 16 bits, flags in upper -// endcaps directly follow this patch in the list - -// types -#define PATCH_GENERIC 0x00000000 // generic flat patch -#define PATCH_CYLINDER 0x00000001 // cylinder -#define PATCH_BEVEL 0x00000002 // bevel -#define PATCH_ENDCAP 0x00000004 // endcap -#define PATCH_HEMISPHERE 0x00000008 // hemisphere -#define PATCH_CONE 0x00000010 // cone -#define PATCH_TRIANGLE 0x00000020 // simple tri, assumes 3x3 patch - -// behaviour styles -#define PATCH_CAP 0x00001000 // flat patch applied as a cap -#define PATCH_SEAM 0x00002000 // flat patch applied as a seam -#define PATCH_THICK 0x00004000 // patch applied as a thick portion - -// styles -#define PATCH_BEZIER 0x00000000 // default bezier -#define PATCH_BSPLINE 0x10000000 // bspline - -#define PATCH_TYPEMASK 0x00000fff // -#define PATCH_BTYPEMASK 0x0000f000 // -#define PATCH_STYLEMASK 0xffff0000 // - -typedef struct { - vec3_t xyz; - float st[2]; - float lightmap[2]; - vec3_t normal; -} drawVert_t; - -// spog - used for patch LOD trees - -struct BTNode_t -{ - BTNode_t *left, *right; - drawVert_t info; - drawVert_t vMid; -}; - -struct BTreeList_t -{ - BTreeList_t *next; - BTNode_t *pBT; - drawVert_t vLeft, vRight; -}; - -struct BTListList_t -{ - BTListList_t *next; - BTreeList_t *list; -}; - -// used in brush primitive AND entities -typedef struct epair_s -{ - struct epair_s *next; - char *key; - char *value; -} epair_t; - -struct brush_s; -typedef struct brush_s brush_t; - -typedef struct { - int width, height; // in control points, not patches - int contents, flags, value, type; - qtexture_t *d_texture; - IShader *pShader; - drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; - brush_t *pSymbiot; - qboolean bSelected; - qboolean bOverlay; - qboolean bDirty; - int nListID; - epair_t *epairs; - // cast this one to an IPluginTexdef if you are using it - // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h - // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? - void *pData; - // spog - curve LOD binary trees and lists - BTNode_t *rowLOD[((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT]; // = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT - BTNode_t *colLOD[((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH]; // = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH - bool rowDirty[((MAX_PATCH_WIDTH-1)-1)/2]; - bool colDirty[((MAX_PATCH_HEIGHT-1)-1)/2]; - bool LODUpdated; - void *drawLists; // pointer to std::list -} patchMesh_t; - -typedef struct brush_s -{ - struct brush_s *prev, *next; // links in active/selected - struct brush_s *oprev, *onext; // links in entity - struct entity_s *owner; - vec3_t mins, maxs; - face_t *brush_faces; - - qboolean bModelFailed; - // - // curve brush extensions - // all are derived from brush_faces - qboolean patchBrush; - qboolean hiddenBrush; - - //int nPatchID; - - patchMesh_t *pPatch; - struct entity_s *pUndoOwner; - - int undoId; //undo ID - int redoId; //redo ID - int ownerId; //entityId of the owner entity for undo - - // TTimo: this is not legal, we are not supposed to put UI toolkit dependant stuff in the interfaces - // NOTE: the grouping stuff never worked, there is embryonary code everywhere though - int numberId; - void* itemOwner; // GtkCTreeNode* ? - - // brush primitive only - epair_t *epairs; - - // brush filtered toggle - bool bFiltered; - bool bCamCulled; - bool bBrushDef; -} brush_t; - -#define MAX_FLAGS 16 - -typedef struct vertmodel_t -{ - float v[3]; - float st[2]; - float normal[3]; -} vertmodel; - -typedef struct triindex_t -{ - int indexes[3]; -} triindex; - -// TTimo: NOTE: we don't have dedicated stuff to copy/allocate/delete this structure like we do for entity_t and brush_t -// could be necessary, I'm adding GString *strSkin that needs to be copied around -// TTimo 04/01/2001 removing the GString* for toolkit-independent interfaces .. cast it .. -typedef struct entitymodel_t -{ - struct entitymodel_t *pNext; - int nTriCount; - //trimodel *pTriList; - //md3Triangle_t *pTriList; - triindex *pTriList; - vertmodel *pVertList; - int numVerts; - int nTextureBind; - void *strSkin; // toolkit-independent .. cast to a GString* - int nSkinWidth; - int nSkinHeight; - int nModelPosition; -} entitymodel; - -// eclass show flags - -#define ECLASS_LIGHT 0x00000001 -#define ECLASS_ANGLE 0x00000002 -#define ECLASS_PATH 0x00000004 -#define ECLASS_MISCMODEL 0x00000008 - -#ifdef USEPLUGINENTITIES -#define ECLASS_PLUGINENTITY 0x00000010 -#endif // USEPLUGINENTITIES - -typedef struct eclass_s -{ - struct eclass_s *next; - char *name; - qboolean fixedsize; - qboolean unknown; // wasn't found in source - vec3_t mins, maxs; - vec3_t color; - texdef_t texdef; - char *comments; - char flagnames[MAX_FLAGS][32]; - - entitymodel *model; - char *modelpath; - //++timo NOTE: I don't know what this is used for exactly. But don't trust it for the real skin paths on models (screws up with long/short path names) - //++hydra NOTE: this, hopefully, will be used to use specific shaders on the bounding boxes of the eclass instead of a color. - char *skinpath; - int nFrame; - unsigned int nShowFlags; - - void* hPlug; -} eclass_t; - -extern eclass_t *eclass; - -/* -** window bits -*/ -#define W_CAMERA 0x0001 -#define W_XY 0x0002 -#define W_XY_OVERLAY 0x0004 -#define W_Z 0x0008 -#define W_TEXTURE 0x0010 -#define W_Z_OVERLAY 0x0020 -#define W_CONSOLE 0x0040 -#define W_ENTITY 0x0080 -#define W_CAMERA_IFON 0x0100 -#define W_XZ 0x0200 //--| only used for patch vertex manip stuff -#define W_YZ 0x0400 //--| -#define W_GROUP 0x0800 -#define W_MEDIA 0x1000 -#define W_ALL 0xFFFFFFFF - -// used in some Drawing routines -enum VIEWTYPE {YZ, XZ, XY}; -const char g_AxisName[3] = { 'X', 'Y', 'Z' }; - -// dynamically allocated string -class string_t -{ -public: - inline string_t() - { - copy(""); - } - inline string_t(const string_t& other) - { - copy(other.m_string); - } - inline string_t(const char* string) - { - copy(string); - } - inline ~string_t() - { - destroy(); - } - inline const string_t& operator=(const string_t& other) - { - destroy(); - copy(other.m_string); - return *this; - } - inline const string_t& operator=(const char* string) - { - destroy(); - copy(string); - return *this; - } - inline bool operator<(const string_t& other) const - { - return compare(other) < 0; - } - inline bool operator>(const string_t& other) const - { - return compare(other) > 0; - } - inline bool operator==(const string_t& other) const - { - return compare(other) == 0; - } - inline bool operator!=(const string_t& other) const - { - return compare(other) != 0; - } - inline const char* c_str() const - { - return m_string; - } -private: - inline void copy(const char* string) - { - m_string = new char[strlen(string)+1]; - strcpy(m_string, string); - } - inline void destroy() - { - delete[] m_string; - } - inline int compare(const string_t& other) const - { - return strcmp(m_string, other.m_string); - } - - char* m_string; -}; - -class filetype_t -{ -public: - filetype_t() - : name(""), pattern("") - {} - filetype_t(const char* _name, const char* _pattern) - : name(_name), pattern(_pattern) - {} - const char* name; - const char* pattern; -}; - - -/* -** Outline bits -*/ -#define OUTLINE_ZBUF 0x01 // zbuffered outline -#define OUTLINE_BSEL 0x02 // selection overlay - -#ifdef USEPLUGINENTITIES -// forward declare this one -class IPluginEntity; -#endif // USEPLUGINENTITIES - -// MODEL - -class IRender; -class ISelect; -class IEdit; - -// NOTE TTimo about ~entity_interfaces_t -// using constructors / destructors on C structs is bad practice -struct entity_interfaces_t -{ - IRender *pRender; - ISelect *pSelect; - IEdit *pEdit; -}; -// MODEL END - -typedef struct entity_s -{ - struct entity_s *prev, *next; - - /*! - \todo can use a brushes list, or the blind data below - for now, blind data should be interpreted as CPtrArray*, only use in the IMAP API - */ - brush_t brushes; // head/tail of list - void *pData; - - int undoId, redoId, entityId; // used for undo/redo - vec3_t origin; - eclass_t *eclass; - epair_t *epairs; - entity_interfaces_t model; -#ifdef USEPLUGINENTITIES - IPluginEntity *pPlugEnt; -#endif // USEPLUGINENTITIES - - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 - // this is cam code addition? - vec3_t color; - - // Arnout: HACK-ish and change for 1.3 (in 1.3 we have a blind data pointer according to TTimo) - float fLightEnvelope1[3]; - float fLightEnvelope2[2]; -} entity_t; - -typedef struct -{ - int p1, p2; - face_t *f1, *f2; -} pedge_t; - -// window system independent camera view code -// NOTE TTimo taken from xy.h -typedef struct -{ - int width, height; - - qboolean timing; - - vec3_t origin; // at center of window - float scale; - - float topclip, bottomclip; - - qboolean d_dirty; -} xy_t; - -// spog - struct used for nodes in filters list -struct bfilter_t //c++ style -{ - bfilter_t *next; - int attribute; // 1=brush->face->pShader->getName() - // 2=brush->pPatch->pShader->getFlags() - // 3=brush->owner->eclass->name - // 4=brush->owner->eclass->nShowFlags - int mask; - char *string; - bool active; -}; - -// djbob: no longer any need to add only to end, versioning removed, it is no longer saved as binary -// IMPORTANT: whenever you update this struct, you need to add the relevant load/save code -// preferences.cpp LoadPref / SavePref -typedef struct -{ - int iTexMenu; // nearest, linear, etc - float fGamma; // gamma for textures - vec3_t colors[COLOR_LAST]; - int exclude; - int include; - texdef_t m_SIIncrement; // increments for the surface inspector - texdef_t m_PIIncrement; // increments for the patch inspector - vec3_t AxisColors[3]; // colors used for X, Y Z axis - // these are in the View > Show menu with Show coordinates - qboolean show_names; - qboolean show_coordinates; - qboolean show_angles; - qboolean show_outline; - qboolean show_axis; - qboolean bNoSelectedOutlines; - bfilter_t *filters; // FIXME spog - might be better in another location? - int iSelectedOutlinesStyle; -} SavedInfo_t; - -typedef enum -{ - sel_brush, - sel_brush_on, - sel_brush_off, - // sel_sticky_brush, - // sel_face, - sel_vertex, - sel_edge, - sel_singlevertex, - sel_curvepoint, - sel_area, - sel_areatall, - sel_facets_on, - sel_facets_off, -} select_t; - -// most of the QE globals are stored in this structure -typedef struct -{ - qboolean d_showgrid; - float d_gridsize; - qboolean d_bSmallGrid; // we use this flag to hack our way into editing of <1 grids - - int d_num_entities; - - entity_t *d_project_entity; - - // defines the boundaries of the current work area - // is used to guess brushes and drop points third coordinate when creating from 2D view - vec3_t d_work_min,d_work_max; - // not stored in registry, default is off - qboolean d_show_work; - - vec3_t d_points[MAX_POINTS]; - int d_numpoints; - pedge_t d_edges[MAX_EDGES]; - int d_numedges; - - int d_num_move_points; - float *d_move_points[4096]; - - qtexture_t *d_qtextures; - // used to speedup access, specially in QERApp_Try_Texture_ForName - // must always be kept up-to-date with d_qtextures* - //++timo FIXME at some point in the future it would even be better to remove d_qtextures and use this instead - GHashTable *d_qtexmap; - - texturewin_t d_texturewin; - - int d_pointfile_display_list; - - xy_t d_xyOld; - - SavedInfo_t d_savedinfo; - - int d_workcount; - - // connect entities uses the last two brushes selected - int d_select_count; - brush_t *d_select_order[2]; - vec3_t d_select_translate; // for dragging w/o making new display lists - select_t d_select_mode; - - int d_parsed_brushes; - - qboolean show_blocks; - int blockSize; - - // NOTE TTimo - // a lot of this data should be in a property bag and available to the other modules through an API - // this is generated from game configuration and the project settings, and should be still be part of it - - // tells if we are internally using brush primitive (texture coordinates and map format) - // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) - // NOTE: must keep the two ones in sync - bool m_bBrushPrimitMode; - - /*! - win32: engine full path. - unix: user home full path + engine dir. - */ - Str m_strHomeGame; - /*! - cache for m_strHomeGame + mod subdirectory. - */ - Str m_strHomeMaps; - - // used while importing brush data from file or memory buffer - // tells if conversion between map format and internal preferences ( m_bBrushPrimitMode ) is needed - qboolean bNeedConvert; - qboolean bOldBrushes; - qboolean bPrimitBrushes; - - vec3_t d_vAreaTL; - vec3_t d_vAreaBR; - - // tells if we are using .INI files for prefs instead of registry - qboolean use_ini; - // even in .INI mode we use the registry for all void* prefs - char use_ini_registry[64]; - // disabled all INI / registry read write .. used when shutting down after registry cleanup - qboolean disable_ini; - - // tells we are using a BSP frontend plugin - qboolean bBSPFrontendPlugin; - - // handle to the console log file - // we use low level I/O to get rid of buffering and have everything on file if we crash - int hLogFile; - - qboolean bTextureCompressionSupported; // is texture compression supported by hardware? - GLint texture_components; - - // temporary values that should be initialised only once at run-time - // there are too many uneccessary calls to Sys_QGL_ExtensionSupported - // NOTE TTimo: those are unused atm (set right, but not used) - // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 - bool m_bOpenGLCompressionSupported; - bool m_bS3CompressionSupported; - - // set to true after OpenGL has been initialized and extensions have been tested - bool m_bOpenGLReady; - -} QEGlobals_t; - -#endif // _QERTYPES_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// qertypes.h +// +// common types +// merged from brush.h, etc. for plugin support +// +#ifndef _QERTYPES_H_ +#define _QERTYPES_H_ + +#ifdef _WIN32 +#include <wtypes.h> +#endif + +#include <GL/gl.h> + +#include "str.h" + +#ifdef _WIN32 +#define PATH_MAX 260 +#endif + +// HACK glib-2.0 +#define NAME_MAX 255 + +typedef bool qboolean; + +#define MAXPOINTS 16 + +// merged from qedefs.h ------ + +#define MAX_EDGES 512 +#define MAX_POINTS 1024 + +#define COLOR_TEXTUREBACK 0 +#define COLOR_GRIDBACK 1 +#define COLOR_GRIDMINOR 2 +#define COLOR_GRIDMAJOR 3 +#define COLOR_CAMERABACK 4 +#define COLOR_ENTITY 5 +#define COLOR_GRIDBLOCK 6 +#define COLOR_GRIDTEXT 7 +#define COLOR_BRUSHES 8 +#define COLOR_SELBRUSHES 9 +#define COLOR_CLIPPER 10 +#define COLOR_VIEWNAME 11 +#define COLOR_SELBRUSHES3D 12 + +#define COLOR_GRIDMINOR_ALT 13 +#define COLOR_GRIDMAJOR_ALT 14 + +#define COLOR_LAST 15 + +// ---------------------------- + +typedef float vec_t; +typedef vec_t vec3_t[3]; + +// turn this on/off to use a static texdef or a memory one +// THIS MUST BE CONSISTENT throughout a whole build of Radiant / modules / plugins +// DO_TEXDEF_ALLOC is more memory efficient, but I suspect it to be wacky on win32 / C runtime etc. +#define DO_TEXDEF_ALLOC 1 +#if DO_TEXDEF_ALLOC + +class texdef_t +{ +private: + char *name; +public: + texdef_t() + { + name = new char[1]; + name[0] = '\0'; + shift[0] = 0.0f; + shift[1] = 0.0f; + rotate = 0.0f; + scale[0] = 1.0f; + scale[1] = 1.0f; + contents = 0; + flags = 0; + value = 0; + } + texdef_t(const texdef_t& other) + { + name = NULL; + SetName(other.name); + shift[0] = other.shift[0]; + shift[1] = other.shift[1]; + rotate = other.rotate; + scale[0] = other.scale[0]; + scale[1] = other.scale[1]; + contents = other.contents; + flags = other.flags; + value = other.value; + } + ~texdef_t() + { + if (name) + { + delete []name; + name = (char*)NULL; + } + } + + void SetName(const char *p) + { + if (name) + { + delete []name; + name = NULL; + } + if (p) + { + name = strcpy(new char[strlen(p)+1], p); + } + else + { + name = new char[1]; + name[0] = '\0'; + } + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name = NULL; + SetName(NULL); + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#else + +// max length of a vfs texture path +#define QPATH 64 +class texdef_t +{ +private: + char name[QPATH]; +public: + texdef_t() { name[0] = '\0'; } + ~texdef_t() { } + + void SetName(const char *p) + { + strncpy(name, p, QPATH); + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name[0] = '\0'; + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#endif + +// forward declare +class IShader; + +// Timo +// new brush primitive texdef +typedef struct brushprimit_texdef_s +{ + vec_t coords[2][3]; +} brushprimit_texdef_t; + +// this structure is used in Radiant to reflect the state of the texture window +// it gives information on current shader and various flags +class texturewin_t +{ +public: + texturewin_t() + { + } + ~texturewin_t() + { + } + int width, height; + int originy; + // add brushprimit_texdef_t for brush primitive coordinates storage + brushprimit_texdef_t brushprimit_texdef; + int m_nTotalHeight; + // surface plugin, must be casted to a IPluginTexdef* + void* pTexdef; + texdef_t texdef; + // shader + // NOTE: never NULL, initialized in Texture_Init + // NOTE: the reference name of the shader is texdef.name (see QERApp_ReloadShaders for an example) + IShader *pShader; +}; + +#define QER_TRANS 0x00000001 +#define QER_NOCARVE 0x00000002 +#define QER_NODRAW 0x00000004 +#define QER_NONSOLID 0x00000008 +#define QER_WATER 0x00000010 +#define QER_LAVA 0x00000020 +#define QER_FOG 0x00000040 +#define QER_ALPHAFUNC 0x00000080 +#define QER_CULL 0x00000100 + + +// describes a GL texture that Radiant uses to represent a shader +// NOTE: all qtexture_t are stored in a main list at g_qeglobals.d_qtextures +// shaders have reference couting, but qtexture_t don't (they're way too deep into Radiant) +typedef struct qtexture_s +{ + struct qtexture_s *next; + // name of the texture file (the physical image file we are using) + // NOTE: used for lookup, must be unique .. vfs path of the texture, lowercase, NO FILE EXTENSION + // ex textures/gothic_wall/iron + // NOTE: the "textures/" prefix might seem unnecessary .. but it's better to stick to the vfs name + char name[64]; + int width, height; + GLuint texture_number; // gl bind number (the qtexture_t are usually loaded and binded by the shaders module) + vec3_t color; // for flat shade mode + qboolean inuse; // true = is present on the level (for the texture browser interface) +} qtexture_t; + +// NOTE: don't trust this definition! +// you should read float points[..][5] +// see NewWinding definition +// WARNING: don't touch anything to this struct unless you looked into winding.cpp and WINDING_SIZE(pt) +#define MAX_POINTS_ON_WINDING 64 +typedef struct +{ + int numpoints; + int maxpoints; + float points[8][5]; // variable sized +} winding_t; + +typedef struct +{ + vec3_t normal; + double dist; + int type; +} plane_t; + +// pShader is a shortcut to the shader +// it's only up-to-date after a Brush_Build call +// to initialize the pShader, use QERApp_Shader_ForName(texdef.name) +typedef struct face_s +{ + struct face_s *next; + struct face_s *prev; + struct face_s *original; //used for vertex movement + vec3_t planepts[3]; + texdef_t texdef; + plane_t plane; + + // Nurail: Face Undo + int undoId; + int redoId; + + winding_t *face_winding; + + vec3_t d_color; + vec_t d_shade; + // calls through here have indirections (pure virtual) + // it would be good if the rendering loop would avoid scanning there (for the GL binding number for example) + IShader *pShader; + //++timo FIXME: remove! + qtexture_t *d_texture; + + // Timo new brush primit texdef + brushprimit_texdef_t brushprimit_texdef; + + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; +} face_t; + +typedef struct { + vec3_t xyz; + float sideST[2]; + float capST[2]; +} curveVertex_t; + +typedef struct { + curveVertex_t v[2]; +} sideVertex_t; + + +#define MIN_PATCH_WIDTH 3 +#define MIN_PATCH_HEIGHT 3 + +#define MAX_PATCH_WIDTH 16 +#define MAX_PATCH_HEIGHT 16 + +// patch type info +// type in lower 16 bits, flags in upper +// endcaps directly follow this patch in the list + +// types +#define PATCH_GENERIC 0x00000000 // generic flat patch +#define PATCH_CYLINDER 0x00000001 // cylinder +#define PATCH_BEVEL 0x00000002 // bevel +#define PATCH_ENDCAP 0x00000004 // endcap +#define PATCH_HEMISPHERE 0x00000008 // hemisphere +#define PATCH_CONE 0x00000010 // cone +#define PATCH_TRIANGLE 0x00000020 // simple tri, assumes 3x3 patch + +// behaviour styles +#define PATCH_CAP 0x00001000 // flat patch applied as a cap +#define PATCH_SEAM 0x00002000 // flat patch applied as a seam +#define PATCH_THICK 0x00004000 // patch applied as a thick portion + +// styles +#define PATCH_BEZIER 0x00000000 // default bezier +#define PATCH_BSPLINE 0x10000000 // bspline + +#define PATCH_TYPEMASK 0x00000fff // +#define PATCH_BTYPEMASK 0x0000f000 // +#define PATCH_STYLEMASK 0xffff0000 // + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; +} drawVert_t; + +// spog - used for patch LOD trees + +struct BTNode_t +{ + BTNode_t *left, *right; + drawVert_t info; + drawVert_t vMid; +}; + +struct BTreeList_t +{ + BTreeList_t *next; + BTNode_t *pBT; + drawVert_t vLeft, vRight; +}; + +struct BTListList_t +{ + BTListList_t *next; + BTreeList_t *list; +}; + +// used in brush primitive AND entities +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +struct brush_s; +typedef struct brush_s brush_t; + +typedef struct { + int width, height; // in control points, not patches + int contents, flags, value, type; + qtexture_t *d_texture; + IShader *pShader; + drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + brush_t *pSymbiot; + qboolean bSelected; + qboolean bOverlay; + qboolean bDirty; + int nListID; + epair_t *epairs; + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; + // spog - curve LOD binary trees and lists + BTNode_t *rowLOD[((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT]; // = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT + BTNode_t *colLOD[((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH]; // = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH + bool rowDirty[((MAX_PATCH_WIDTH-1)-1)/2]; + bool colDirty[((MAX_PATCH_HEIGHT-1)-1)/2]; + bool LODUpdated; + void *drawLists; // pointer to std::list +} patchMesh_t; + +typedef struct brush_s +{ + struct brush_s *prev, *next; // links in active/selected + struct brush_s *oprev, *onext; // links in entity + struct entity_s *owner; + vec3_t mins, maxs; + face_t *brush_faces; + + qboolean bModelFailed; + // + // curve brush extensions + // all are derived from brush_faces + qboolean patchBrush; + qboolean hiddenBrush; + + //int nPatchID; + + patchMesh_t *pPatch; + struct entity_s *pUndoOwner; + + int undoId; //undo ID + int redoId; //redo ID + int ownerId; //entityId of the owner entity for undo + + // TTimo: this is not legal, we are not supposed to put UI toolkit dependant stuff in the interfaces + // NOTE: the grouping stuff never worked, there is embryonary code everywhere though + int numberId; + void* itemOwner; // GtkCTreeNode* ? + + // brush primitive only + epair_t *epairs; + + // brush filtered toggle + bool bFiltered; + bool bCamCulled; + bool bBrushDef; +} brush_t; + +#define MAX_FLAGS 16 + +typedef struct vertmodel_t +{ + float v[3]; + float st[2]; + float normal[3]; +} vertmodel; + +typedef struct triindex_t +{ + int indexes[3]; +} triindex; + +// TTimo: NOTE: we don't have dedicated stuff to copy/allocate/delete this structure like we do for entity_t and brush_t +// could be necessary, I'm adding GString *strSkin that needs to be copied around +// TTimo 04/01/2001 removing the GString* for toolkit-independent interfaces .. cast it .. +typedef struct entitymodel_t +{ + struct entitymodel_t *pNext; + int nTriCount; + //trimodel *pTriList; + //md3Triangle_t *pTriList; + triindex *pTriList; + vertmodel *pVertList; + int numVerts; + int nTextureBind; + void *strSkin; // toolkit-independent .. cast to a GString* + int nSkinWidth; + int nSkinHeight; + int nModelPosition; +} entitymodel; + +// eclass show flags + +#define ECLASS_LIGHT 0x00000001 +#define ECLASS_ANGLE 0x00000002 +#define ECLASS_PATH 0x00000004 +#define ECLASS_MISCMODEL 0x00000008 + +#ifdef USEPLUGINENTITIES +#define ECLASS_PLUGINENTITY 0x00000010 +#endif // USEPLUGINENTITIES + +typedef struct eclass_s +{ + struct eclass_s *next; + char *name; + qboolean fixedsize; + qboolean unknown; // wasn't found in source + vec3_t mins, maxs; + vec3_t color; + texdef_t texdef; + char *comments; + char flagnames[MAX_FLAGS][32]; + + entitymodel *model; + char *modelpath; + //++timo NOTE: I don't know what this is used for exactly. But don't trust it for the real skin paths on models (screws up with long/short path names) + //++hydra NOTE: this, hopefully, will be used to use specific shaders on the bounding boxes of the eclass instead of a color. + char *skinpath; + int nFrame; + unsigned int nShowFlags; + + void* hPlug; +} eclass_t; + +extern eclass_t *eclass; + +/* +** window bits +*/ +#define W_CAMERA 0x0001 +#define W_XY 0x0002 +#define W_XY_OVERLAY 0x0004 +#define W_Z 0x0008 +#define W_TEXTURE 0x0010 +#define W_Z_OVERLAY 0x0020 +#define W_CONSOLE 0x0040 +#define W_ENTITY 0x0080 +#define W_CAMERA_IFON 0x0100 +#define W_XZ 0x0200 //--| only used for patch vertex manip stuff +#define W_YZ 0x0400 //--| +#define W_GROUP 0x0800 +#define W_MEDIA 0x1000 +#define W_ALL 0xFFFFFFFF + +// used in some Drawing routines +enum VIEWTYPE {YZ, XZ, XY}; +const char g_AxisName[3] = { 'X', 'Y', 'Z' }; + +// dynamically allocated string +class string_t +{ +public: + inline string_t() + { + copy(""); + } + inline string_t(const string_t& other) + { + copy(other.m_string); + } + inline string_t(const char* string) + { + copy(string); + } + inline ~string_t() + { + destroy(); + } + inline const string_t& operator=(const string_t& other) + { + destroy(); + copy(other.m_string); + return *this; + } + inline const string_t& operator=(const char* string) + { + destroy(); + copy(string); + return *this; + } + inline bool operator<(const string_t& other) const + { + return compare(other) < 0; + } + inline bool operator>(const string_t& other) const + { + return compare(other) > 0; + } + inline bool operator==(const string_t& other) const + { + return compare(other) == 0; + } + inline bool operator!=(const string_t& other) const + { + return compare(other) != 0; + } + inline const char* c_str() const + { + return m_string; + } +private: + inline void copy(const char* string) + { + m_string = new char[strlen(string)+1]; + strcpy(m_string, string); + } + inline void destroy() + { + delete[] m_string; + } + inline int compare(const string_t& other) const + { + return strcmp(m_string, other.m_string); + } + + char* m_string; +}; + +class filetype_t +{ +public: + filetype_t() + : name(""), pattern("") + {} + filetype_t(const char* _name, const char* _pattern) + : name(_name), pattern(_pattern) + {} + const char* name; + const char* pattern; +}; + + +/* +** Outline bits +*/ +#define OUTLINE_ZBUF 0x01 // zbuffered outline +#define OUTLINE_BSEL 0x02 // selection overlay + +#ifdef USEPLUGINENTITIES +// forward declare this one +class IPluginEntity; +#endif // USEPLUGINENTITIES + +// MODEL + +class IRender; +class ISelect; +class IEdit; + +// NOTE TTimo about ~entity_interfaces_t +// using constructors / destructors on C structs is bad practice +struct entity_interfaces_t +{ + IRender *pRender; + ISelect *pSelect; + IEdit *pEdit; +}; +// MODEL END + +typedef struct entity_s +{ + struct entity_s *prev, *next; + + /*! + \todo can use a brushes list, or the blind data below + for now, blind data should be interpreted as CPtrArray*, only use in the IMAP API + */ + brush_t brushes; // head/tail of list + void *pData; + + int undoId, redoId, entityId; // used for undo/redo + vec3_t origin; + eclass_t *eclass; + epair_t *epairs; + entity_interfaces_t model; +#ifdef USEPLUGINENTITIES + IPluginEntity *pPlugEnt; +#endif // USEPLUGINENTITIES + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 + // this is cam code addition? + vec3_t color; + + // Arnout: HACK-ish and change for 1.3 (in 1.3 we have a blind data pointer according to TTimo) + float fLightEnvelope1[3]; + float fLightEnvelope2[2]; +} entity_t; + +typedef struct +{ + int p1, p2; + face_t *f1, *f2; +} pedge_t; + +// window system independent camera view code +// NOTE TTimo taken from xy.h +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; + + float topclip, bottomclip; + + qboolean d_dirty; +} xy_t; + +// spog - struct used for nodes in filters list +struct bfilter_t //c++ style +{ + bfilter_t *next; + int attribute; // 1=brush->face->pShader->getName() + // 2=brush->pPatch->pShader->getFlags() + // 3=brush->owner->eclass->name + // 4=brush->owner->eclass->nShowFlags + int mask; + char *string; + bool active; +}; + +// djbob: no longer any need to add only to end, versioning removed, it is no longer saved as binary +// IMPORTANT: whenever you update this struct, you need to add the relevant load/save code +// preferences.cpp LoadPref / SavePref +typedef struct +{ + int iTexMenu; // nearest, linear, etc + float fGamma; // gamma for textures + vec3_t colors[COLOR_LAST]; + int exclude; + int include; + texdef_t m_SIIncrement; // increments for the surface inspector + texdef_t m_PIIncrement; // increments for the patch inspector + vec3_t AxisColors[3]; // colors used for X, Y Z axis + // these are in the View > Show menu with Show coordinates + qboolean show_names; + qboolean show_coordinates; + qboolean show_angles; + qboolean show_outline; + qboolean show_axis; + qboolean bNoSelectedOutlines; + bfilter_t *filters; // FIXME spog - might be better in another location? + int iSelectedOutlinesStyle; +} SavedInfo_t; + +typedef enum +{ + sel_brush, + sel_brush_on, + sel_brush_off, + // sel_sticky_brush, + // sel_face, + sel_vertex, + sel_edge, + sel_singlevertex, + sel_curvepoint, + sel_area, + sel_areatall, + sel_facets_on, + sel_facets_off, +} select_t; + +// most of the QE globals are stored in this structure +typedef struct +{ + qboolean d_showgrid; + float d_gridsize; + qboolean d_bSmallGrid; // we use this flag to hack our way into editing of <1 grids + + int d_num_entities; + + entity_t *d_project_entity; + + // defines the boundaries of the current work area + // is used to guess brushes and drop points third coordinate when creating from 2D view + vec3_t d_work_min,d_work_max; + // not stored in registry, default is off + qboolean d_show_work; + + vec3_t d_points[MAX_POINTS]; + int d_numpoints; + pedge_t d_edges[MAX_EDGES]; + int d_numedges; + + int d_num_move_points; + float *d_move_points[4096]; + + qtexture_t *d_qtextures; + // used to speedup access, specially in QERApp_Try_Texture_ForName + // must always be kept up-to-date with d_qtextures* + //++timo FIXME at some point in the future it would even be better to remove d_qtextures and use this instead + GHashTable *d_qtexmap; + + texturewin_t d_texturewin; + + int d_pointfile_display_list; + + xy_t d_xyOld; + + SavedInfo_t d_savedinfo; + + int d_workcount; + + // connect entities uses the last two brushes selected + int d_select_count; + brush_t *d_select_order[2]; + vec3_t d_select_translate; // for dragging w/o making new display lists + select_t d_select_mode; + + int d_parsed_brushes; + + qboolean show_blocks; + int blockSize; + + // NOTE TTimo + // a lot of this data should be in a property bag and available to the other modules through an API + // this is generated from game configuration and the project settings, and should be still be part of it + + // tells if we are internally using brush primitive (texture coordinates and map format) + // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) + // NOTE: must keep the two ones in sync + bool m_bBrushPrimitMode; + + /*! + win32: engine full path. + unix: user home full path + engine dir. + */ + Str m_strHomeGame; + /*! + cache for m_strHomeGame + mod subdirectory. + */ + Str m_strHomeMaps; + + // used while importing brush data from file or memory buffer + // tells if conversion between map format and internal preferences ( m_bBrushPrimitMode ) is needed + qboolean bNeedConvert; + qboolean bOldBrushes; + qboolean bPrimitBrushes; + + vec3_t d_vAreaTL; + vec3_t d_vAreaBR; + + // tells if we are using .INI files for prefs instead of registry + qboolean use_ini; + // even in .INI mode we use the registry for all void* prefs + char use_ini_registry[64]; + // disabled all INI / registry read write .. used when shutting down after registry cleanup + qboolean disable_ini; + + // tells we are using a BSP frontend plugin + qboolean bBSPFrontendPlugin; + + // handle to the console log file + // we use low level I/O to get rid of buffering and have everything on file if we crash + int hLogFile; + + qboolean bTextureCompressionSupported; // is texture compression supported by hardware? + GLint texture_components; + + // temporary values that should be initialised only once at run-time + // there are too many uneccessary calls to Sys_QGL_ExtensionSupported + // NOTE TTimo: those are unused atm (set right, but not used) + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 + bool m_bOpenGLCompressionSupported; + bool m_bS3CompressionSupported; + + // set to true after OpenGL has been initialized and extensions have been tested + bool m_bOpenGLReady; + +} QEGlobals_t; + +#endif // _QERTYPES_H_ diff --git a/include/qsysprintf.h b/include/qsysprintf.h index 83622784..a8d2874a 100644 --- a/include/qsysprintf.h +++ b/include/qsysprintf.h @@ -1,67 +1,67 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __QSYSPRINTF_H__ -#define __QSYSPRINTF_H__ - -/*! -this header is provided in libs/ in an attempt to provide a common API -for all the diagnostic printing / fatal error situations - -this is oriented at synapse server targets ONLY -synapse clients should not include this, as they are supposed to go -through the function tables to report print diagnostics -(or use Syn_Printf for situations where the func table may not be available) - -each server target implements that in it's own way. Radiant logs to -a file and sends to the console, q3map prints to stdout and to the -XML network stream, etc. -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -// NOTE: might want to switch to bits if needed -#define SYS_VRB 0 ///< verbose support (on/off) -#define SYS_STD 1 ///< standard print level - this is the default -#define SYS_WRN 2 ///< warnings -#define SYS_ERR 3 ///< error -#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) - -/*! -those are the real implementation -*/ -void Sys_Printf_VA (const char *text, va_list args); ///< matches PFN_SYN_PRINTF_VA prototype -void Sys_FPrintf_VA (int level, const char *text, va_list args); - -/*! -this is easy to call, wrappers around va_list version -*/ -void Sys_Printf (const char *text, ...); -void Sys_FPrintf (int flag, const char *text, ...); - -#if defined(__cplusplus) -}; -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __QSYSPRINTF_H__ +#define __QSYSPRINTF_H__ + +/*! +this header is provided in libs/ in an attempt to provide a common API +for all the diagnostic printing / fatal error situations + +this is oriented at synapse server targets ONLY +synapse clients should not include this, as they are supposed to go +through the function tables to report print diagnostics +(or use Syn_Printf for situations where the func table may not be available) + +each server target implements that in it's own way. Radiant logs to +a file and sends to the console, q3map prints to stdout and to the +XML network stream, etc. +*/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +// NOTE: might want to switch to bits if needed +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) + +/*! +those are the real implementation +*/ +void Sys_Printf_VA (const char *text, va_list args); ///< matches PFN_SYN_PRINTF_VA prototype +void Sys_FPrintf_VA (int level, const char *text, va_list args); + +/*! +this is easy to call, wrappers around va_list version +*/ +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/include/stl_check.h b/include/stl_check.h index b30481df..b6def1db 100644 --- a/include/stl_check.h +++ b/include/stl_check.h @@ -1,60 +1,60 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 header is used to make sure the STL we are using is what we expect -this allows to catch some weird errors early at compile time -*/ - -#ifdef Q_NO_STLPORT - -// not using STLPort (gcc 3.x build) -using namespace std; - -#else - -#ifndef _STLPORT_VERSION -#error "Can't find _STLPORT_VERSION, check you are compiling against STLPort" -#endif - -#if !defined(_STLP_DONT_USE_EXCEPTIONS) -#error exc -#endif - -#if !defined(_STLP_NO_NAMESPACES) -#error namespace -#endif - -#if !defined(_STLP_NO_IOSTREAMS) -#error io -#endif - -// now check a few more things (paranoid) -// if you use our custom STLPort distribution it should be alright though -#if !defined(_STLP_DONT_USE_EXCEPTIONS) || !defined(_STLP_NO_NAMESPACES) || !defined(_STLP_NO_IOSTREAMS) -#error "There is something broken in your STLPort config" -#endif - -#ifdef _WIN32 -#pragma warning(disable : 4786) -#endif - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 header is used to make sure the STL we are using is what we expect +this allows to catch some weird errors early at compile time +*/ + +#ifdef Q_NO_STLPORT + +// not using STLPort (gcc 3.x build) +using namespace std; + +#else + +#ifndef _STLPORT_VERSION +#error "Can't find _STLPORT_VERSION, check you are compiling against STLPort" +#endif + +#if !defined(_STLP_DONT_USE_EXCEPTIONS) +#error exc +#endif + +#if !defined(_STLP_NO_NAMESPACES) +#error namespace +#endif + +#if !defined(_STLP_NO_IOSTREAMS) +#error io +#endif + +// now check a few more things (paranoid) +// if you use our custom STLPort distribution it should be alright though +#if !defined(_STLP_DONT_USE_EXCEPTIONS) || !defined(_STLP_NO_NAMESPACES) || !defined(_STLP_NO_IOSTREAMS) +#error "There is something broken in your STLPort config" +#endif + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#endif diff --git a/include/stream_version.h b/include/stream_version.h index d9271854..17ce6339 100644 --- a/include/stream_version.h +++ b/include/stream_version.h @@ -1,3 +1,3 @@ -// version defines for q3map stream -#define Q3MAP_STREAM_VERSION "1" - +// version defines for q3map stream +#define Q3MAP_STREAM_VERSION "1" + diff --git a/include/version.h b/include/version.h index f3905933..2ef2606b 100644 --- a/include/version.h +++ b/include/version.h @@ -1,4 +1,4 @@ -// generated header, see makeversion.py -#define RADIANT_VERSION "1.4.0" -#define RADIANT_MINOR_VERSION "0" -#define RADIANT_MAJOR_VERSION "4" +// generated header, see makeversion.py +#define RADIANT_VERSION "1.4.0" +#define RADIANT_MINOR_VERSION "0" +#define RADIANT_MAJOR_VERSION "4" diff --git a/install/games/default_project.proj b/install/games/default_project.proj new file mode 100644 index 00000000..9738c418 --- /dev/null +++ b/install/games/default_project.proj @@ -0,0 +1,62 @@ +<?xml version="1.0"?> +<!DOCTYPE project SYSTEM "dtds/project.dtd"> +<!-- +project template +the $* strings will be expanded following these rules: +$TEMPLATEapppath: path to the Radiant .. C:\Program Files\Gtkradiant +$TEMPLATEenginepath: path to the engine .. C:\quake3\ C:\Program Files\Quake III Arena\ /usr/local/games/quake3/ +$TEMPLATEtoolspath: path to the tools directory (enginepath)radiant + (NOTE: on win32 tools directory is usually where the editor is .. but it's not true on linux) +$TEMPLATEuserhomepath: on linux, the directory with write permissions for saving maps etc. + on win32, == $TEMPLATEenginepath +$TEMPLATEbasedir: base game dir + +Note : Default project settings are for single player... this can be changed throught the projects select in the File Menu + +--> +<project> +<key name="version" value="2"/> +<key name="basepath" value="$TEMPLATEenginepath$TEMPLATEbasedir/"/> +<key name="rshcmd" value=""/> +<key name="remotebasepath" value="$TEMPLATEenginepath$TEMPLATEbasedir/"/> +<key name="entitypath" value="$TEMPLATEtoolspath$TEMPLATEbasedir/scripts/entities.def"/> +<key name="texturepath" value="$TEMPLATEenginepath$TEMPLATEbasedir/textures/"/> +<key name="autosave" value="$TEMPLATEuserhomepath$TEMPLATEbasedir/maps/autosave.map"/> +<key name="mapspath" value="$TEMPLATEuserhomepath$TEMPLATEbasedir/maps/"/> + +<key name="bsp_Q3Map2: (single) BSP -meta" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $"/> + +<key name="bsp_Q3Map2: (single) -vis" value="! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis $" /> + +<key name="bsp_Q3Map2: (single test) -vis -fast" value="! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -fast $" /> + +<key name="bsp_Q3Map2: (single test) -light -faster" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -faster $" /> + +<key name="bsp_Q3Map2: (single test) -light -fast" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast $" /> + +<key name="bsp_Q3Map2: (single) -light -super 2" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -super 2 $" /> + +<key name="bsp_Q3Map2: (single) -light -fast -super 2" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -super 2 $" /> + +<key name="bsp_Q3Map2: (single) -light -fast -super 2 -filter" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -super 2 -filter $" /> + +<key name="bsp_Q3Map2: (single) -light -super 2 -filter -bounce 8" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -super 2 -filter -bounce 8 $" /> + +<key name="bsp_Q3Map2: (single) -light -super 2 -filter -bounce 1" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -super 2 -filter -bounce 1 $" /> + +<key name="bsp_Q3Map2: (single) -light -fast -super 2 -filter -bounce 8" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -super 2 -filter -bounce 8 $" /> + +<key name="bsp_Q3Map2: (test) BSP -meta, -vis, -light -fast -filter" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -filter $" /> + +<key name="bsp_Q3Map2: (test) BSP -meta, -vis -fast, -light -fast -super 2 -filter" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt -fast $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -super 2 -filter $" /> + +<key name="bsp_Q3Map2: (final) BSP -meta, -vis, -light -fast -filter -super 2" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -filter -super 2 $" /> + +<key name="bsp_Q3Map2: (final) BSP -meta, -vis, -light -fast -filter -super 2" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -filter -super 2 $" /> + +<key name="bsp_Q3Map2: (final) BSP -meta, -vis, -light -fast -filter -super 2 -bounce 8" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -fast -super 2 -filter -bounce 8 $" /> + +<key name="bsp_Q3Map2: (simulate old style -light -extra) BSP -meta, -vis, -light -super 2" value="! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -meta $ && ! "$TEMPLATEapppathq3map2" # -game quake3 -fs_basepath "$TEMPLATEenginepath" -vis -saveprt $ && ! "$TEMPLATEapppathq3map2" -v # -game quake3 -fs_basepath "$TEMPLATEenginepath" -light -super 2 $" /> + +<key name="bsp_AAS: compile AAS" value="! "$TEMPLATEapppathbspc" -optimize -threads 2 -forcesidesvisible -bsp2aas $" /> +</project> diff --git a/install/games/qz.game b/install/games/q3.game similarity index 57% rename from install/games/qz.game rename to install/games/q3.game index 5e116a9c..fc3e82fa 100644 --- a/install/games/qz.game +++ b/install/games/q3.game @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="iso-8859-1" standalone="yes"?> <game - name="QuakeZero" - enginepath =".." + name="Quake III Arena" + enginepath="/usr/local/games/quake3" gametools="/home/timo/SVN/ZeroRadiant/install/games" - gamename="quakezero" + gamename="quake3" /> diff --git a/libs/bytebool.h b/libs/bytebool.h index 9253bd35..e0617893 100644 --- a/libs/bytebool.h +++ b/libs/bytebool.h @@ -1,20 +1,20 @@ -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ - -// bool is a C++ type -// if we are compiling for C, use an enum - -// this header is not really meant for direct inclusion, -// it is used by mathlib and cmdlib - -#ifdef __cplusplus -typedef bool qboolean; -#define qtrue true -#define qfalse false -#else -typedef enum { qfalse, qtrue } qboolean; -#endif - -typedef unsigned char byte; - -#endif +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +// bool is a C++ type +// if we are compiling for C, use an enum + +// this header is not really meant for direct inclusion, +// it is used by mathlib and cmdlib + +#ifdef __cplusplus +typedef bool qboolean; +#define qtrue true +#define qfalse false +#else +typedef enum { qfalse, qtrue } qboolean; +#endif + +typedef unsigned char byte; + +#endif diff --git a/libs/cmdlib.h b/libs/cmdlib.h index 84833fcd..92d985ae 100644 --- a/libs/cmdlib.h +++ b/libs/cmdlib.h @@ -1,111 +1,111 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// -// start of shared cmdlib stuff -// - -#ifndef __CMDLIB__ -#define __CMDLIB__ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <time.h> -#include <stdarg.h> -#include <limits.h> -#ifdef _WIN32 - #define PATH_MAX 260 -#endif - -// some easy portability crap -#ifdef _WIN32 - #include <direct.h> - #define Q_mkdir(a,b) _mkdir(a) -#else - #include <sys/stat.h> - #define Q_mkdir(a,b) mkdir(a,b) -#endif - -#ifdef __cplusplus - typedef bool qboolean; -#endif - -// NOTE TTimo: is this worth anything? -#ifndef __BYTEBOOL__ -#define __BYTEBOOL__ - -#ifndef __cplusplus - typedef enum {false, true} boolean; -#else - typedef unsigned char boolean; -#endif - -typedef unsigned char byte; - -#endif // __BYTEBOOL__ - -void DefaultExtension( char *path, char *extension ); -void DefaultPath( char *path, char *basepath ); -void StripFilename( char *path ); -void StripExtension( char *path ); -void ExtractFilePath( const char *path, char *dest ); -void ExtractFileName( const char *path, char *dest ); -void ExtractFileBase( const char *path, char *dest ); -void ExtractFileExtension( const char *path, char *dest ); -/*! -\brief create all directories leading to a file path. if you pass a directory, terminate it with a '/' -*/ -void CreateDirectoryPath (const char *path); - -short BigShort (short l); -short LittleShort (short l); -int BigLong (int l); -int LittleLong (int l); -float BigFloat (float l); -float LittleFloat (float l); -void *qmalloc (size_t size); -void* qblockmalloc(size_t nSize); - -void ConvertDOSToUnixName( char *dst, const char *src ); -#ifdef __cplusplus - char* StrDup(char* pStr); -#endif -char* StrDup(const char* pStr); - -// TTimo started adding portability code: -// return true if spawning was successful, false otherwise -// on win32 we have a bCreateConsole flag to create a new console or run inside the current one -//boolean Q_Exec(const char* pCmd, boolean bCreateConsole); -// execute a system command: -// cmd: the command to run -// cmdline: the command line -// NOTE TTimo following are win32 specific: -// execdir: the directory to execute in -// bCreateConsole: spawn a new console or not -// return values; -// if the spawn was fine -// TODO TTimo add functionality to track the process until it dies -bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole); - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// start of shared cmdlib stuff +// + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <stdarg.h> +#include <limits.h> +#ifdef _WIN32 + #define PATH_MAX 260 +#endif + +// some easy portability crap +#ifdef _WIN32 + #include <direct.h> + #define Q_mkdir(a,b) _mkdir(a) +#else + #include <sys/stat.h> + #define Q_mkdir(a,b) mkdir(a,b) +#endif + +#ifdef __cplusplus + typedef bool qboolean; +#endif + +// NOTE TTimo: is this worth anything? +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +#ifndef __cplusplus + typedef enum {false, true} boolean; +#else + typedef unsigned char boolean; +#endif + +typedef unsigned char byte; + +#endif // __BYTEBOOL__ + +void DefaultExtension( char *path, char *extension ); +void DefaultPath( char *path, char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileName( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); +/*! +\brief create all directories leading to a file path. if you pass a directory, terminate it with a '/' +*/ +void CreateDirectoryPath (const char *path); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); +void *qmalloc (size_t size); +void* qblockmalloc(size_t nSize); + +void ConvertDOSToUnixName( char *dst, const char *src ); +#ifdef __cplusplus + char* StrDup(char* pStr); +#endif +char* StrDup(const char* pStr); + +// TTimo started adding portability code: +// return true if spawning was successful, false otherwise +// on win32 we have a bCreateConsole flag to create a new console or run inside the current one +//boolean Q_Exec(const char* pCmd, boolean bCreateConsole); +// execute a system command: +// cmd: the command to run +// cmdline: the command line +// NOTE TTimo following are win32 specific: +// execdir: the directory to execute in +// bCreateConsole: spawn a new console or not +// return values; +// if the spawn was fine +// TODO TTimo add functionality to track the process until it dies +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole); + +#endif diff --git a/libs/ddslib.h b/libs/ddslib.h index 246e31be..3f5f124c 100644 --- a/libs/ddslib.h +++ b/libs/ddslib.h @@ -1,250 +1,250 @@ -/* ----------------------------------------------------------------------------- - -DDS Library - -Based on code from Nvidia's DDS example: -http://www.nvidia.com/object/dxtc_decompression_code.html - -Copyright (c) 2003 Randy Reddig -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 DDSLIB_H -#define DDSLIB_H - - - -/* dependencies */ -#include <stdio.h> -#include <memory.h> - - - -/* c++ marker */ -#ifdef __cplusplus -extern "C" -{ -#endif - - - -/* dds definition */ -typedef enum -{ - DDS_PF_ARGB8888, - DDS_PF_DXT1, - DDS_PF_DXT2, - DDS_PF_DXT3, - DDS_PF_DXT4, - DDS_PF_DXT5, - DDS_PF_UNKNOWN -} -ddsPF_t; - - -/* 16bpp stuff */ -#define DDS_LOW_5 0x001F; -#define DDS_MID_6 0x07E0; -#define DDS_HIGH_5 0xF800; -#define DDS_MID_555 0x03E0; -#define DDS_HI_555 0x7C00; - - -/* structures */ -typedef struct ddsColorKey_s -{ - unsigned int colorSpaceLowValue; - unsigned int colorSpaceHighValue; -} -ddsColorKey_t; - - -typedef struct ddsCaps_s -{ - unsigned int caps1; - unsigned int caps2; - unsigned int caps3; - unsigned int caps4; -} -ddsCaps_t; - - -typedef struct ddsMultiSampleCaps_s -{ - unsigned short flipMSTypes; - unsigned short bltMSTypes; -} -ddsMultiSampleCaps_t; - - -typedef struct ddsPixelFormat_s -{ - unsigned int size; - unsigned int flags; - unsigned int fourCC; - union - { - unsigned int rgbBitCount; - unsigned int yuvBitCount; - unsigned int zBufferBitDepth; - unsigned int alphaBitDepth; - unsigned int luminanceBitCount; - unsigned int bumpBitCount; - unsigned int privateFormatBitCount; - }; - union - { - unsigned int rBitMask; - unsigned int yBitMask; - unsigned int stencilBitDepth; - unsigned int luminanceBitMask; - unsigned int bumpDuBitMask; - unsigned int operations; - }; - union - { - unsigned int gBitMask; - unsigned int uBitMask; - unsigned int zBitMask; - unsigned int bumpDvBitMask; - ddsMultiSampleCaps_t multiSampleCaps; - }; - union - { - unsigned int bBitMask; - unsigned int vBitMask; - unsigned int stencilBitMask; - unsigned int bumpLuminanceBitMask; - }; - union - { - unsigned int rgbAlphaBitMask; - unsigned int yuvAlphaBitMask; - unsigned int luminanceAlphaBitMask; - unsigned int rgbZBitMask; - unsigned int yuvZBitMask; - }; -} -ddsPixelFormat_t; - - -typedef struct ddsBuffer_s -{ - /* magic: 'dds ' */ - char magic[ 4 ]; - - /* directdraw surface */ - unsigned int size; - unsigned int flags; - unsigned int height; - unsigned int width; - union - { - int pitch; - unsigned int linearSize; - }; - unsigned int backBufferCount; - union - { - unsigned int mipMapCount; - unsigned int refreshRate; - unsigned int srcVBHandle; - }; - unsigned int alphaBitDepth; - unsigned int reserved; - void *surface; - union - { - ddsColorKey_t ckDestOverlay; - unsigned int emptyFaceColor; - }; - ddsColorKey_t ckDestBlt; - ddsColorKey_t ckSrcOverlay; - ddsColorKey_t ckSrcBlt; - union - { - ddsPixelFormat_t pixelFormat; - unsigned int fvf; - }; - ddsCaps_t ddsCaps; - unsigned int textureStage; - - /* data (Varying size) */ - unsigned char data[ 4 ]; -} -ddsBuffer_t; - - -typedef struct ddsColorBlock_s -{ - unsigned short colors[ 2 ]; - unsigned char row[ 4 ]; -} -ddsColorBlock_t; - - -typedef struct ddsAlphaBlockExplicit_s -{ - unsigned short row[ 4 ]; -} -ddsAlphaBlockExplicit_t; - - -typedef struct ddsAlphaBlock3BitLinear_s -{ - unsigned char alpha0; - unsigned char alpha1; - unsigned char stuff[ 6 ]; -} -ddsAlphaBlock3BitLinear_t; - - -typedef struct ddsColor_s -{ - unsigned char r, g, b, a; -} -ddsColor_t; - - - -/* public functions */ -int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ); -int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ); - - - -/* end marker */ -#ifdef __cplusplus -} -#endif - -#endif +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +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 DDSLIB_H +#define DDSLIB_H + + + +/* dependencies */ +#include <stdio.h> +#include <memory.h> + + + +/* c++ marker */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* dds definition */ +typedef enum +{ + DDS_PF_ARGB8888, + DDS_PF_DXT1, + DDS_PF_DXT2, + DDS_PF_DXT3, + DDS_PF_DXT4, + DDS_PF_DXT5, + DDS_PF_UNKNOWN +} +ddsPF_t; + + +/* 16bpp stuff */ +#define DDS_LOW_5 0x001F; +#define DDS_MID_6 0x07E0; +#define DDS_HIGH_5 0xF800; +#define DDS_MID_555 0x03E0; +#define DDS_HI_555 0x7C00; + + +/* structures */ +typedef struct ddsColorKey_s +{ + unsigned int colorSpaceLowValue; + unsigned int colorSpaceHighValue; +} +ddsColorKey_t; + + +typedef struct ddsCaps_s +{ + unsigned int caps1; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; +} +ddsCaps_t; + + +typedef struct ddsMultiSampleCaps_s +{ + unsigned short flipMSTypes; + unsigned short bltMSTypes; +} +ddsMultiSampleCaps_t; + + +typedef struct ddsPixelFormat_s +{ + unsigned int size; + unsigned int flags; + unsigned int fourCC; + union + { + unsigned int rgbBitCount; + unsigned int yuvBitCount; + unsigned int zBufferBitDepth; + unsigned int alphaBitDepth; + unsigned int luminanceBitCount; + unsigned int bumpBitCount; + unsigned int privateFormatBitCount; + }; + union + { + unsigned int rBitMask; + unsigned int yBitMask; + unsigned int stencilBitDepth; + unsigned int luminanceBitMask; + unsigned int bumpDuBitMask; + unsigned int operations; + }; + union + { + unsigned int gBitMask; + unsigned int uBitMask; + unsigned int zBitMask; + unsigned int bumpDvBitMask; + ddsMultiSampleCaps_t multiSampleCaps; + }; + union + { + unsigned int bBitMask; + unsigned int vBitMask; + unsigned int stencilBitMask; + unsigned int bumpLuminanceBitMask; + }; + union + { + unsigned int rgbAlphaBitMask; + unsigned int yuvAlphaBitMask; + unsigned int luminanceAlphaBitMask; + unsigned int rgbZBitMask; + unsigned int yuvZBitMask; + }; +} +ddsPixelFormat_t; + + +typedef struct ddsBuffer_s +{ + /* magic: 'dds ' */ + char magic[ 4 ]; + + /* directdraw surface */ + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + union + { + int pitch; + unsigned int linearSize; + }; + unsigned int backBufferCount; + union + { + unsigned int mipMapCount; + unsigned int refreshRate; + unsigned int srcVBHandle; + }; + unsigned int alphaBitDepth; + unsigned int reserved; + void *surface; + union + { + ddsColorKey_t ckDestOverlay; + unsigned int emptyFaceColor; + }; + ddsColorKey_t ckDestBlt; + ddsColorKey_t ckSrcOverlay; + ddsColorKey_t ckSrcBlt; + union + { + ddsPixelFormat_t pixelFormat; + unsigned int fvf; + }; + ddsCaps_t ddsCaps; + unsigned int textureStage; + + /* data (Varying size) */ + unsigned char data[ 4 ]; +} +ddsBuffer_t; + + +typedef struct ddsColorBlock_s +{ + unsigned short colors[ 2 ]; + unsigned char row[ 4 ]; +} +ddsColorBlock_t; + + +typedef struct ddsAlphaBlockExplicit_s +{ + unsigned short row[ 4 ]; +} +ddsAlphaBlockExplicit_t; + + +typedef struct ddsAlphaBlock3BitLinear_s +{ + unsigned char alpha0; + unsigned char alpha1; + unsigned char stuff[ 6 ]; +} +ddsAlphaBlock3BitLinear_t; + + +typedef struct ddsColor_s +{ + unsigned char r, g, b, a; +} +ddsColor_t; + + + +/* public functions */ +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ); +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ); + + + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/ddslib/ddslib.c b/libs/ddslib/ddslib.c index e7bfeb2b..bf1a9f15 100644 --- a/libs/ddslib/ddslib.c +++ b/libs/ddslib/ddslib.c @@ -1,781 +1,781 @@ -/* ----------------------------------------------------------------------------- - -DDS Library - -Based on code from Nvidia's DDS example: -http://www.nvidia.com/object/dxtc_decompression_code.html - -Copyright (c) 2003 Randy Reddig -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 DDSLIB_C - - - -/* dependencies */ -#include "ddslib.h" - - - -/* endian tomfoolery */ -typedef union -{ - float f; - char c[ 4 ]; -} -floatSwapUnion; - - -#ifndef __BIG_ENDIAN__ - #ifdef _SGI_SOURCE - #define __BIG_ENDIAN__ - #endif -#endif - - -#ifdef __BIG_ENDIAN__ - - int DDSBigLong( int src ) { return src; } - short DDSBigShort( short src ) { return src; } - float DDSBigFloat( float src ) { return src; } - - int DDSLittleLong( int src ) - { - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); - } - - short DDSLittleShort( short src ) - { - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); - } - - float DDSLittleFloat( 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 DDSLittleLong( int src ) { return src; } - short DDSLittleShort( short src ) { return src; } - float DDSLittleFloat( float src ) { return src; } - - int DDSBigLong( int src ) - { - return ((src & 0xFF000000) >> 24) | - ((src & 0x00FF0000) >> 8) | - ((src & 0x0000FF00) << 8) | - ((src & 0x000000FF) << 24); - } - - short DDSBigShort( short src ) - { - return ((src & 0xFF00) >> 8) | - ((src & 0x00FF) << 8); - } - - float DDSBigFloat( 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__*/ - - - -/* -DDSDecodePixelFormat() -determines which pixel format the dds texture is in -*/ - -static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf ) -{ - unsigned int fourCC; - - - /* dummy check */ - if( dds == NULL || pf == NULL ) - return; - - /* extract fourCC */ - fourCC = dds->pixelFormat.fourCC; - - /* test it */ - if( fourCC == 0 ) - *pf = DDS_PF_ARGB8888; - else if( fourCC == *((unsigned int*) "DXT1") ) - *pf = DDS_PF_DXT1; - else if( fourCC == *((unsigned int*) "DXT2") ) - *pf = DDS_PF_DXT2; - else if( fourCC == *((unsigned int*) "DXT3") ) - *pf = DDS_PF_DXT3; - else if( fourCC == *((unsigned int*) "DXT4") ) - *pf = DDS_PF_DXT4; - else if( fourCC == *((unsigned int*) "DXT5") ) - *pf = DDS_PF_DXT5; - else - *pf = DDS_PF_UNKNOWN; -} - - - -/* -DDSGetInfo() -extracts relevant info from a dds texture, returns 0 on success -*/ - -int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ) -{ - /* dummy test */ - if( dds == NULL ) - return -1; - - /* test dds header */ - if( *((int*) dds->magic) != *((int*) "DDS ") ) - return -1; - if( DDSLittleLong( dds->size ) != 124 ) - return -1; - - /* extract width and height */ - if( width != NULL ) - *width = DDSLittleLong( dds->width ); - if( height != NULL ) - *height = DDSLittleLong( dds->height ); - - /* get pixel format */ - DDSDecodePixelFormat( dds, pf ); - - /* return ok */ - return 0; -} - - - -/* -DDSGetColorBlockColors() -extracts colors from a dds color block -*/ - -static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] ) -{ - unsigned short word; - - - /* color 0 */ - word = DDSLittleShort( block->colors[ 0 ] ); - colors[ 0 ].a = 0xff; - - /* extract rgb bits */ - colors[ 0 ].b = (unsigned char) word; - colors[ 0 ].b <<= 3; - colors[ 0 ].b |= (colors[ 0 ].b >> 5); - word >>= 5; - colors[ 0 ].g = (unsigned char) word; - colors[ 0 ].g <<= 2; - colors[ 0 ].g |= (colors[ 0 ].g >> 5); - word >>= 6; - colors[ 0 ].r = (unsigned char) word; - colors[ 0 ].r <<= 3; - colors[ 0 ].r |= (colors[ 0 ].r >> 5); - - /* same for color 1 */ - word = DDSLittleShort( block->colors[ 1 ] ); - colors[ 1 ].a = 0xff; - - /* extract rgb bits */ - colors[ 1 ].b = (unsigned char) word; - colors[ 1 ].b <<= 3; - colors[ 1 ].b |= (colors[ 1 ].b >> 5); - word >>= 5; - colors[ 1 ].g = (unsigned char) word; - colors[ 1 ].g <<= 2; - colors[ 1 ].g |= (colors[ 1 ].g >> 5); - word >>= 6; - colors[ 1 ].r = (unsigned char) word; - colors[ 1 ].r <<= 3; - colors[ 1 ].r |= (colors[ 1 ].r >> 5); - - /* use this for all but the super-freak math method */ - if( block->colors[ 0 ] > block->colors[ 1 ] ) - { - /* four-color block: derive the other two colors. - 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 - these two bit codes correspond to the 2-bit fields - stored in the 64-bit block. */ - - word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3; - /* no +1 for rounding */ - /* as bits have been shifted to 888 */ - colors[ 2 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3; - colors[ 2 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3; - colors[ 2 ].b = (unsigned char) word; - colors[ 2 ].a = 0xff; - - word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3; - colors[ 3 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3; - colors[ 3 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3; - colors[ 3 ].b = (unsigned char) word; - colors[ 3 ].a = 0xff; - } - else - { - /* three-color block: derive the other color. - 00 = color 0, 01 = color 1, 10 = color 2, - 11 = transparent. - These two bit codes correspond to the 2-bit fields - stored in the 64-bit block */ - - word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2; - colors[ 2 ].r = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2; - colors[ 2 ].g = (unsigned char) word; - word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2; - colors[ 2 ].b = (unsigned char) word; - colors[ 2 ].a = 0xff; - - /* random color to indicate alpha */ - colors[ 3 ].r = 0x00; - colors[ 3 ].g = 0xff; - colors[ 3 ].b = 0xff; - colors[ 3 ].a = 0x00; - } -} - - - -/* -DDSDecodeColorBlock() -decodes a dds color block -fixme: make endian-safe -*/ - -static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] ) -{ - int r, n; - unsigned int bits; - unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ - int shift[] = { 0, 2, 4, 6 }; - - - /* r steps through lines in y */ - for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */ - { - /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ - - /* n steps through pixels */ - for( n = 0; n < 4; n++ ) - { - bits = block->row[ r ] & masks[ n ]; - bits >>= shift[ n ]; - - switch( bits ) - { - case 0: - *pixel = colors[ 0 ]; - pixel++; - break; - - case 1: - *pixel = colors[ 1 ]; - pixel++; - break; - - case 2: - *pixel = colors[ 2 ]; - pixel++; - break; - - case 3: - *pixel = colors[ 3 ]; - pixel++; - break; - - default: - /* invalid */ - pixel++; - break; - } - } - } -} - - - -/* -DDSDecodeAlphaExplicit() -decodes a dds explicit alpha block -*/ - -static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero ) -{ - int row, pix; - unsigned short word; - ddsColor_t color; - - - /* clear color */ - color.r = 0; - color.g = 0; - color.b = 0; - - /* walk rows */ - for( row = 0; row < 4; row++, pixel += (width - 4) ) - { - word = DDSLittleShort( alphaBlock->row[ row ] ); - - /* walk pixels */ - for( pix = 0; pix < 4; pix++ ) - { - /* zero the alpha bits of image pixel */ - *pixel &= alphaZero; - color.a = word & 0x000F; - color.a = color.a | (color.a << 4); - *pixel |= *((unsigned int*) &color); - word >>= 4; /* move next bits to lowest 4 */ - pixel++; /* move to next pixel in the row */ - - } - } -} - - - -/* -DDSDecodeAlpha3BitLinear() -decodes interpolated alpha block -*/ - -static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero ) -{ - - int row, pix; - unsigned int stuff; - unsigned char bits[ 4 ][ 4 ]; - unsigned short alphas[ 8 ]; - ddsColor_t aColors[ 4 ][ 4 ]; - - - /* get initial alphas */ - alphas[ 0 ] = alphaBlock->alpha0; - alphas[ 1 ] = alphaBlock->alpha1; - - /* 8-alpha block */ - if( alphas[ 0 ] > alphas[ 1 ] ) - { - /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ - alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ - alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ - alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ - alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ - alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ - alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ - } - - /* 6-alpha block */ - else - { - /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ - alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ - alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ - alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ - alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ - alphas[ 6 ] = 0; /* bit code 110 */ - alphas[ 7 ] = 255; /* bit code 111 */ - } - - /* decode 3-bit fields into array of 16 bytes with same value */ - - /* first two rows of 4 pixels each */ - stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ])); - - bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - - /* last two rows */ - stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ - - bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007); - stuff >>= 3; - bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007); - - /* decode the codes into alpha values */ - for( row = 0; row < 4; row++ ) - { - for( pix=0; pix < 4; pix++ ) - { - aColors[ row ][ pix ].r = 0; - aColors[ row ][ pix ].g = 0; - aColors[ row ][ pix ].b = 0; - aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ]; - } - } - - /* write out alpha values to the image bits */ - for( row = 0; row < 4; row++, pixel += width-4 ) - { - for( pix = 0; pix < 4; pix++ ) - { - /* zero the alpha bits of image pixel */ - *pixel &= alphaZero; - - /* or the bits into the prev. nulled alpha */ - *pixel |= *((unsigned int*) &(aColors[ row ][ pix ])); - pixel++; - } - } -} - - - -/* -DDSDecompressDXT1() -decompresses a dxt1 format texture -*/ - -static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel; - ddsColorBlock_t *block; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - DDSGetColorBlockColors( block, colors ); - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT3() -decompresses a dxt3 format texture -*/ - -static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel, alphaZero; - ddsColorBlock_t *block; - ddsAlphaBlockExplicit_t *alphaBlock; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* create zero alpha */ - colors[ 0 ].a = 0; - colors[ 0 ].r = 0xFF; - colors[ 0 ].g = 0xFF; - colors[ 0 ].b = 0xFF; - alphaZero = *((unsigned int*) &colors[ 0 ]); - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block, 1 block for alpha, 1 block for color */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - /* get alpha block */ - alphaBlock = (ddsAlphaBlockExplicit_t*) block; - - /* get color block */ - block++; - DDSGetColorBlockColors( block, colors ); - - /* decode color block */ - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - - /* overwrite alpha bits with alpha block */ - DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT5() -decompresses a dxt5 format texture -*/ - -static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y, xBlocks, yBlocks; - unsigned int *pixel, alphaZero; - ddsColorBlock_t *block; - ddsAlphaBlock3BitLinear_t *alphaBlock; - ddsColor_t colors[ 4 ]; - - - /* setup */ - xBlocks = width / 4; - yBlocks = height / 4; - - /* create zero alpha */ - colors[ 0 ].a = 0; - colors[ 0 ].r = 0xFF; - colors[ 0 ].g = 0xFF; - colors[ 0 ].b = 0xFF; - alphaZero = *((unsigned int*) &colors[ 0 ]); - - /* walk y */ - for( y = 0; y < yBlocks; y++ ) - { - /* 8 bytes per block, 1 block for alpha, 1 block for color */ - block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); - - /* walk x */ - for( x = 0; x < xBlocks; x++, block++ ) - { - /* get alpha block */ - alphaBlock = (ddsAlphaBlock3BitLinear_t*) block; - - /* get color block */ - block++; - DDSGetColorBlockColors( block, colors ); - - /* decode color block */ - pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); - DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); - - /* overwrite alpha bits with alpha block */ - DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompressDXT2() -decompresses a dxt2 format texture (fixme: un-premultiply alpha) -*/ - -static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int r; - - - /* decompress dxt3 first */ - r = DDSDecompressDXT3( dds, width, height, pixels ); - - /* return to sender */ - return r; -} - - - -/* -DDSDecompressDXT4() -decompresses a dxt4 format texture (fixme: un-premultiply alpha) -*/ - -static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int r; - - - /* decompress dxt5 first */ - r = DDSDecompressDXT5( dds, width, height, pixels ); - - /* return to sender */ - return r; -} - - - -/* -DDSDecompressARGB8888() -decompresses an argb 8888 format texture -*/ - -static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) -{ - int x, y; - unsigned char *in, *out; - - - /* setup */ - in = dds->data; - out = pixels; - - /* walk y */ - for( y = 0; y < height; y++ ) - { - /* walk x */ - for( x = 0; x < width; x++ ) - { - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - *out++ = *in++; - } - } - - /* return ok */ - return 0; -} - - - -/* -DDSDecompress() -decompresses a dds texture into an rgba image buffer, returns 0 on success -*/ - -int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ) -{ - int width, height, r; - ddsPF_t pf; - - - /* get dds info */ - r = DDSGetInfo( dds, &width, &height, &pf ); - if( r ) - return r; - - /* decompress */ - switch( pf ) - { - case DDS_PF_ARGB8888: - /* fixme: support other [a]rgb formats */ - r = DDSDecompressARGB8888( dds, width, height, pixels ); - break; - - case DDS_PF_DXT1: - r = DDSDecompressDXT1( dds, width, height, pixels ); - break; - - case DDS_PF_DXT2: - r = DDSDecompressDXT2( dds, width, height, pixels ); - break; - - case DDS_PF_DXT3: - r = DDSDecompressDXT3( dds, width, height, pixels ); - break; - - case DDS_PF_DXT4: - r = DDSDecompressDXT4( dds, width, height, pixels ); - break; - - case DDS_PF_DXT5: - r = DDSDecompressDXT5( dds, width, height, pixels ); - break; - - default: - case DDS_PF_UNKNOWN: - memset( pixels, 0xFF, width * height * 4 ); - r = -1; - break; - } - - /* return to sender */ - return r; -} - +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +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 DDSLIB_C + + + +/* dependencies */ +#include "ddslib.h" + + + +/* endian tomfoolery */ +typedef union +{ + float f; + char c[ 4 ]; +} +floatSwapUnion; + + +#ifndef __BIG_ENDIAN__ + #ifdef _SGI_SOURCE + #define __BIG_ENDIAN__ + #endif +#endif + + +#ifdef __BIG_ENDIAN__ + + int DDSBigLong( int src ) { return src; } + short DDSBigShort( short src ) { return src; } + float DDSBigFloat( float src ) { return src; } + + int DDSLittleLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSLittleShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSLittleFloat( 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 DDSLittleLong( int src ) { return src; } + short DDSLittleShort( short src ) { return src; } + float DDSLittleFloat( float src ) { return src; } + + int DDSBigLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSBigShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSBigFloat( 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__*/ + + + +/* +DDSDecodePixelFormat() +determines which pixel format the dds texture is in +*/ + +static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf ) +{ + unsigned int fourCC; + + + /* dummy check */ + if( dds == NULL || pf == NULL ) + return; + + /* extract fourCC */ + fourCC = dds->pixelFormat.fourCC; + + /* test it */ + if( fourCC == 0 ) + *pf = DDS_PF_ARGB8888; + else if( fourCC == *((unsigned int*) "DXT1") ) + *pf = DDS_PF_DXT1; + else if( fourCC == *((unsigned int*) "DXT2") ) + *pf = DDS_PF_DXT2; + else if( fourCC == *((unsigned int*) "DXT3") ) + *pf = DDS_PF_DXT3; + else if( fourCC == *((unsigned int*) "DXT4") ) + *pf = DDS_PF_DXT4; + else if( fourCC == *((unsigned int*) "DXT5") ) + *pf = DDS_PF_DXT5; + else + *pf = DDS_PF_UNKNOWN; +} + + + +/* +DDSGetInfo() +extracts relevant info from a dds texture, returns 0 on success +*/ + +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ) +{ + /* dummy test */ + if( dds == NULL ) + return -1; + + /* test dds header */ + if( *((int*) dds->magic) != *((int*) "DDS ") ) + return -1; + if( DDSLittleLong( dds->size ) != 124 ) + return -1; + + /* extract width and height */ + if( width != NULL ) + *width = DDSLittleLong( dds->width ); + if( height != NULL ) + *height = DDSLittleLong( dds->height ); + + /* get pixel format */ + DDSDecodePixelFormat( dds, pf ); + + /* return ok */ + return 0; +} + + + +/* +DDSGetColorBlockColors() +extracts colors from a dds color block +*/ + +static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] ) +{ + unsigned short word; + + + /* color 0 */ + word = DDSLittleShort( block->colors[ 0 ] ); + colors[ 0 ].a = 0xff; + + /* extract rgb bits */ + colors[ 0 ].b = (unsigned char) word; + colors[ 0 ].b <<= 3; + colors[ 0 ].b |= (colors[ 0 ].b >> 5); + word >>= 5; + colors[ 0 ].g = (unsigned char) word; + colors[ 0 ].g <<= 2; + colors[ 0 ].g |= (colors[ 0 ].g >> 5); + word >>= 6; + colors[ 0 ].r = (unsigned char) word; + colors[ 0 ].r <<= 3; + colors[ 0 ].r |= (colors[ 0 ].r >> 5); + + /* same for color 1 */ + word = DDSLittleShort( block->colors[ 1 ] ); + colors[ 1 ].a = 0xff; + + /* extract rgb bits */ + colors[ 1 ].b = (unsigned char) word; + colors[ 1 ].b <<= 3; + colors[ 1 ].b |= (colors[ 1 ].b >> 5); + word >>= 5; + colors[ 1 ].g = (unsigned char) word; + colors[ 1 ].g <<= 2; + colors[ 1 ].g |= (colors[ 1 ].g >> 5); + word >>= 6; + colors[ 1 ].r = (unsigned char) word; + colors[ 1 ].r <<= 3; + colors[ 1 ].r |= (colors[ 1 ].r >> 5); + + /* use this for all but the super-freak math method */ + if( block->colors[ 0 ] > block->colors[ 1 ] ) + { + /* four-color block: derive the other two colors. + 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 + these two bit codes correspond to the 2-bit fields + stored in the 64-bit block. */ + + word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3; + /* no +1 for rounding */ + /* as bits have been shifted to 888 */ + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3; + colors[ 3 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3; + colors[ 3 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3; + colors[ 3 ].b = (unsigned char) word; + colors[ 3 ].a = 0xff; + } + else + { + /* three-color block: derive the other color. + 00 = color 0, 01 = color 1, 10 = color 2, + 11 = transparent. + These two bit codes correspond to the 2-bit fields + stored in the 64-bit block */ + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2; + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + /* random color to indicate alpha */ + colors[ 3 ].r = 0x00; + colors[ 3 ].g = 0xff; + colors[ 3 ].b = 0xff; + colors[ 3 ].a = 0x00; + } +} + + + +/* +DDSDecodeColorBlock() +decodes a dds color block +fixme: make endian-safe +*/ + +static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] ) +{ + int r, n; + unsigned int bits; + unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ + int shift[] = { 0, 2, 4, 6 }; + + + /* r steps through lines in y */ + for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */ + { + /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ + + /* n steps through pixels */ + for( n = 0; n < 4; n++ ) + { + bits = block->row[ r ] & masks[ n ]; + bits >>= shift[ n ]; + + switch( bits ) + { + case 0: + *pixel = colors[ 0 ]; + pixel++; + break; + + case 1: + *pixel = colors[ 1 ]; + pixel++; + break; + + case 2: + *pixel = colors[ 2 ]; + pixel++; + break; + + case 3: + *pixel = colors[ 3 ]; + pixel++; + break; + + default: + /* invalid */ + pixel++; + break; + } + } + } +} + + + +/* +DDSDecodeAlphaExplicit() +decodes a dds explicit alpha block +*/ + +static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero ) +{ + int row, pix; + unsigned short word; + ddsColor_t color; + + + /* clear color */ + color.r = 0; + color.g = 0; + color.b = 0; + + /* walk rows */ + for( row = 0; row < 4; row++, pixel += (width - 4) ) + { + word = DDSLittleShort( alphaBlock->row[ row ] ); + + /* walk pixels */ + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + color.a = word & 0x000F; + color.a = color.a | (color.a << 4); + *pixel |= *((unsigned int*) &color); + word >>= 4; /* move next bits to lowest 4 */ + pixel++; /* move to next pixel in the row */ + + } + } +} + + + +/* +DDSDecodeAlpha3BitLinear() +decodes interpolated alpha block +*/ + +static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero ) +{ + + int row, pix; + unsigned int stuff; + unsigned char bits[ 4 ][ 4 ]; + unsigned short alphas[ 8 ]; + ddsColor_t aColors[ 4 ][ 4 ]; + + + /* get initial alphas */ + alphas[ 0 ] = alphaBlock->alpha0; + alphas[ 1 ] = alphaBlock->alpha1; + + /* 8-alpha block */ + if( alphas[ 0 ] > alphas[ 1 ] ) + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ + alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ + alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ + alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ + alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ + alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ + } + + /* 6-alpha block */ + else + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ + alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ + alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ + alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ + alphas[ 6 ] = 0; /* bit code 110 */ + alphas[ 7 ] = 255; /* bit code 111 */ + } + + /* decode 3-bit fields into array of 16 bytes with same value */ + + /* first two rows of 4 pixels each */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ])); + + bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* last two rows */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ + + bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* decode the codes into alpha values */ + for( row = 0; row < 4; row++ ) + { + for( pix=0; pix < 4; pix++ ) + { + aColors[ row ][ pix ].r = 0; + aColors[ row ][ pix ].g = 0; + aColors[ row ][ pix ].b = 0; + aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ]; + } + } + + /* write out alpha values to the image bits */ + for( row = 0; row < 4; row++, pixel += width-4 ) + { + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + + /* or the bits into the prev. nulled alpha */ + *pixel |= *((unsigned int*) &(aColors[ row ][ pix ])); + pixel++; + } + } +} + + + +/* +DDSDecompressDXT1() +decompresses a dxt1 format texture +*/ + +static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel; + ddsColorBlock_t *block; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + DDSGetColorBlockColors( block, colors ); + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT3() +decompresses a dxt3 format texture +*/ + +static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlockExplicit_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlockExplicit_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT5() +decompresses a dxt5 format texture +*/ + +static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlock3BitLinear_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlock3BitLinear_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT2() +decompresses a dxt2 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt3 first */ + r = DDSDecompressDXT3( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressDXT4() +decompresses a dxt4 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt5 first */ + r = DDSDecompressDXT5( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressARGB8888() +decompresses an argb 8888 format texture +*/ + +static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y; + unsigned char *in, *out; + + + /* setup */ + in = dds->data; + out = pixels; + + /* walk y */ + for( y = 0; y < height; y++ ) + { + /* walk x */ + for( x = 0; x < width; x++ ) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompress() +decompresses a dds texture into an rgba image buffer, returns 0 on success +*/ + +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ) +{ + int width, height, r; + ddsPF_t pf; + + + /* get dds info */ + r = DDSGetInfo( dds, &width, &height, &pf ); + if( r ) + return r; + + /* decompress */ + switch( pf ) + { + case DDS_PF_ARGB8888: + /* fixme: support other [a]rgb formats */ + r = DDSDecompressARGB8888( dds, width, height, pixels ); + break; + + case DDS_PF_DXT1: + r = DDSDecompressDXT1( dds, width, height, pixels ); + break; + + case DDS_PF_DXT2: + r = DDSDecompressDXT2( dds, width, height, pixels ); + break; + + case DDS_PF_DXT3: + r = DDSDecompressDXT3( dds, width, height, pixels ); + break; + + case DDS_PF_DXT4: + r = DDSDecompressDXT4( dds, width, height, pixels ); + break; + + case DDS_PF_DXT5: + r = DDSDecompressDXT5( dds, width, height, pixels ); + break; + + default: + case DDS_PF_UNKNOWN: + memset( pixels, 0xFF, width * height * 4 ); + r = -1; + break; + } + + /* return to sender */ + return r; +} + diff --git a/libs/igl_to_qgl.h b/libs/igl_to_qgl.h index a71ecd2e..633cf478 100644 --- a/libs/igl_to_qgl.h +++ b/libs/igl_to_qgl.h @@ -1,806 +1,806 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -/* -IGL tp QGL mapping header -Copyright (C) 2002 Splash Damage Ltd. -*/ - -#ifndef _IGL_TO_QGL_H_ -#define _IGL_TO_QGL_H_ - -#ifdef _WIN32 -#include <wtypes.h> -#endif - -enum VIEWTYPE {YZ, XZ, XY}; - -#include "igl.h" - -#ifndef APIENTRY - #define APIENTRY -#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 * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); -void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); - -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); - -extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ) -{ -/* - // initialze the qgl functions - qglAccum = NULL; - qglAlphaFunc = g_QglTable->m_pfn_qglAlphaFunc; - qglAreTexturesResident = NULL; - qglArrayElement = NULL; - qglBegin = g_QglTable->m_pfn_qglBegin; - qglBindTexture = g_QglTable->m_pfn_qglBindTexture; - qglBitmap = NULL; - qglBlendFunc = g_QglTable->m_pfn_qglBlendFunc; - qglCallList = g_QglTable->m_pfn_qglCallList; - qglCallLists = g_QglTable->m_pfn_qglCallLists; - qglClear = g_QglTable->m_pfn_qglClear; - qglClearAccum = NULL; - qglClearColor = g_QglTable->m_pfn_qglClearColor; - qglClearDepth = g_QglTable->m_pfn_qglClearDepth; - qglClearIndex = NULL; - qglClearStencil = NULL; - qglClipPlane = NULL; - qglColor3b = NULL; - qglColor3bv = NULL; - qglColor3d = NULL; - qglColor3dv = NULL; - qglColor3f = g_QglTable->m_pfn_qglColor3f; - qglColor3fv = g_QglTable->m_pfn_qglColor3fv; - 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 = g_QglTable->m_pfn_qglColor4f; - qglColor4fv = g_QglTable->m_pfn_qglColor4fv; - 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 = g_QglTable->m_pfn_qglCullFace; - qglDeleteLists = g_QglTable->m_pfn_qglDeleteLists; - qglDeleteTextures = g_QglTable->m_pfn_qglDeleteTextures; - qglDepthFunc = g_QglTable->m_pfn_qglDepthFunc; - qglDepthMask = g_QglTable->m_pfn_qglDepthMask; - qglDepthRange = NULL; - qglDisable = g_QglTable->m_pfn_qglDisable; - qglDisableClientState = NULL; - qglDrawArrays = NULL; - qglDrawBuffer = NULL; - qglDrawElements = NULL; - qglDrawPixels = NULL; - qglEdgeFlag = NULL; - qglEdgeFlagPointer = NULL; - qglEdgeFlagv = NULL; - qglEnable = g_QglTable->m_pfn_qglEnable; - qglEnableClientState = NULL; - qglEnd = g_QglTable->m_pfn_qglEnd; - qglEndList = g_QglTable->m_pfn_qglEndList; - 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 = g_QglTable->m_pfn_qglFogf; - qglFogfv = g_QglTable->m_pfn_qglFogfv; - qglFogi = g_QglTable->m_pfn_qglFogi; - qglFogiv = NULL; - qglFrontFace = NULL; - qglFrustum = NULL; - qglGenLists = g_QglTable->m_pfn_qglGenLists; - qglGenTextures = g_QglTable->m_pfn_qglGenTextures; - 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 = g_QglTable->m_pfn_qglHint; - 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 = g_QglTable->m_pfn_qglLightfv; - qglLighti = NULL; - qglLightiv = NULL; - qglLineStipple = g_QglTable->m_pfn_qglLineStipple; - qglLineWidth = g_QglTable->m_pfn_qglLineWidth; - qglListBase = g_QglTable->m_pfn_qglListBase; - qglLoadIdentity = g_QglTable->m_pfn_qglLoadIdentity; - 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 = g_QglTable->m_pfn_qglMaterialf; - qglMaterialfv = g_QglTable->m_pfn_qglMaterialfv; - qglMateriali = NULL; - qglMaterialiv = NULL; - qglMatrixMode = g_QglTable->m_pfn_qglMatrixMode; - qglMultMatrixd = NULL; - qglMultMatrixf = g_QglTable->m_pfn_qglMultMatrixf; - qglNewList = g_QglTable->m_pfn_qglNewList; - qglNormal3b = NULL; - qglNormal3bv = NULL; - qglNormal3d = NULL; - qglNormal3dv = NULL; - qglNormal3f = g_QglTable->m_pfn_qglNormal3f; - qglNormal3fv = g_QglTable->m_pfn_qglNormal3fv; - qglNormal3i = NULL; - qglNormal3iv = NULL; - qglNormal3s = NULL; - qglNormal3sv = NULL; - qglNormalPointer = NULL; - qglOrtho = g_QglTable->m_pfn_qglOrtho; - qglPassThrough = NULL; - qglPixelMapfv = NULL; - qglPixelMapuiv = NULL; - qglPixelMapusv = NULL; - qglPixelStoref = NULL; - qglPixelStorei = NULL; - qglPixelTransferf = NULL; - qglPixelTransferi = NULL; - qglPixelZoom = NULL; - qglPointSize = g_QglTable->m_pfn_qglPointSize; - qglPolygonMode = g_QglTable->m_pfn_qglPolygonMode; - qglPolygonOffset = NULL; - qglPolygonStipple = NULL; - qglPopAttrib = g_QglTable->m_pfn_qglPopAttrib; - qglPopClientAttrib = NULL; - qglPopMatrix = g_QglTable->m_pfn_qglPopMatrix; - qglPopName = NULL; - qglPrioritizeTextures = NULL; - qglPushAttrib = g_QglTable->m_pfn_qglPushAttrib; - qglPushClientAttrib = NULL; - qglPushMatrix = g_QglTable->m_pfn_qglPushMatrix; - 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 = g_QglTable->m_pfn_qglRasterPos3fv; - 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 = g_QglTable->m_pfn_qglRotated; - qglRotatef = g_QglTable->m_pfn_qglRotatef; - qglScaled = NULL; - qglScalef = g_QglTable->m_pfn_qglScalef; - qglScissor = g_QglTable->m_pfn_qglScissor; - qglSelectBuffer = NULL; - qglShadeModel = g_QglTable->m_pfn_qglShadeModel; - 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 = g_QglTable->m_pfn_qglTexCoord2f; - qglTexCoord2fv = g_QglTable->m_pfn_qglTexCoord2fv; - 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 = g_QglTable->m_pfn_qglTexEnvf; - qglTexEnvfv = NULL; - qglTexEnvi = NULL; - qglTexEnviv = NULL; - qglTexGend = NULL; - qglTexGendv = NULL; - qglTexGenf = g_QglTable->m_pfn_qglTexGenf; - qglTexGenfv = NULL; - qglTexGeni = NULL; - qglTexGeniv = NULL; - qglTexImage1D = g_QglTable->m_pfn_qglTexImage1D; - qglTexImage2D = g_QglTable->m_pfn_qglTexImage2D; - qglTexParameterf = g_QglTable->m_pfn_qglTexParameterf; - qglTexParameterfv = g_QglTable->m_pfn_qglTexParameterfv; - qglTexParameteri = g_QglTable->m_pfn_qglTexParameteri; - qglTexParameteriv = g_QglTable->m_pfn_qglTexParameteriv; - qglTexSubImage1D = g_QglTable->m_pfn_qglTexSubImage1D; - qglTexSubImage2D = g_QglTable->m_pfn_qglTexSubImage2D; - qglTranslated = g_QglTable->m_pfn_qglTranslated; - qglTranslatef = g_QglTable->m_pfn_qglTranslatef; - qglVertex2d = NULL; - qglVertex2dv = NULL; - qglVertex2f = g_QglTable->m_pfn_qglVertex2f; - qglVertex2fv = NULL; - qglVertex2i = NULL; - qglVertex2iv = NULL; - qglVertex2s = NULL; - qglVertex2sv = NULL; - qglVertex3d = NULL; - qglVertex3dv = NULL; - qglVertex3f = g_QglTable->m_pfn_qglVertex3f; - qglVertex3fv = g_QglTable->m_pfn_qglVertex3fv; - 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 = g_QglTable->m_pfn_qglViewport; - - qglPointParameterfEXT = NULL; - qglPointParameterfvEXT = NULL; - qglColorTableEXT = NULL; - - qglMTexCoord2fSGIS = NULL; - qglSelectTextureSGIS = 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; -*/ -} - -#endif // _IGL_TO_QGL_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +IGL tp QGL mapping header +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _IGL_TO_QGL_H_ +#define _IGL_TO_QGL_H_ + +#ifdef _WIN32 +#include <wtypes.h> +#endif + +enum VIEWTYPE {YZ, XZ, XY}; + +#include "igl.h" + +#ifndef APIENTRY + #define APIENTRY +#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 * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +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); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ) +{ +/* + // initialze the qgl functions + qglAccum = NULL; + qglAlphaFunc = g_QglTable->m_pfn_qglAlphaFunc; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = g_QglTable->m_pfn_qglBegin; + qglBindTexture = g_QglTable->m_pfn_qglBindTexture; + qglBitmap = NULL; + qglBlendFunc = g_QglTable->m_pfn_qglBlendFunc; + qglCallList = g_QglTable->m_pfn_qglCallList; + qglCallLists = g_QglTable->m_pfn_qglCallLists; + qglClear = g_QglTable->m_pfn_qglClear; + qglClearAccum = NULL; + qglClearColor = g_QglTable->m_pfn_qglClearColor; + qglClearDepth = g_QglTable->m_pfn_qglClearDepth; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = g_QglTable->m_pfn_qglColor3f; + qglColor3fv = g_QglTable->m_pfn_qglColor3fv; + 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 = g_QglTable->m_pfn_qglColor4f; + qglColor4fv = g_QglTable->m_pfn_qglColor4fv; + 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 = g_QglTable->m_pfn_qglCullFace; + qglDeleteLists = g_QglTable->m_pfn_qglDeleteLists; + qglDeleteTextures = g_QglTable->m_pfn_qglDeleteTextures; + qglDepthFunc = g_QglTable->m_pfn_qglDepthFunc; + qglDepthMask = g_QglTable->m_pfn_qglDepthMask; + qglDepthRange = NULL; + qglDisable = g_QglTable->m_pfn_qglDisable; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = g_QglTable->m_pfn_qglEnable; + qglEnableClientState = NULL; + qglEnd = g_QglTable->m_pfn_qglEnd; + qglEndList = g_QglTable->m_pfn_qglEndList; + 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 = g_QglTable->m_pfn_qglFogf; + qglFogfv = g_QglTable->m_pfn_qglFogfv; + qglFogi = g_QglTable->m_pfn_qglFogi; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = g_QglTable->m_pfn_qglGenLists; + qglGenTextures = g_QglTable->m_pfn_qglGenTextures; + 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 = g_QglTable->m_pfn_qglHint; + 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 = g_QglTable->m_pfn_qglLightfv; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = g_QglTable->m_pfn_qglLineStipple; + qglLineWidth = g_QglTable->m_pfn_qglLineWidth; + qglListBase = g_QglTable->m_pfn_qglListBase; + qglLoadIdentity = g_QglTable->m_pfn_qglLoadIdentity; + 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 = g_QglTable->m_pfn_qglMaterialf; + qglMaterialfv = g_QglTable->m_pfn_qglMaterialfv; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = g_QglTable->m_pfn_qglMatrixMode; + qglMultMatrixd = NULL; + qglMultMatrixf = g_QglTable->m_pfn_qglMultMatrixf; + qglNewList = g_QglTable->m_pfn_qglNewList; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = g_QglTable->m_pfn_qglNormal3f; + qglNormal3fv = g_QglTable->m_pfn_qglNormal3fv; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = g_QglTable->m_pfn_qglOrtho; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = g_QglTable->m_pfn_qglPointSize; + qglPolygonMode = g_QglTable->m_pfn_qglPolygonMode; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = g_QglTable->m_pfn_qglPopAttrib; + qglPopClientAttrib = NULL; + qglPopMatrix = g_QglTable->m_pfn_qglPopMatrix; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = g_QglTable->m_pfn_qglPushAttrib; + qglPushClientAttrib = NULL; + qglPushMatrix = g_QglTable->m_pfn_qglPushMatrix; + 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 = g_QglTable->m_pfn_qglRasterPos3fv; + 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 = g_QglTable->m_pfn_qglRotated; + qglRotatef = g_QglTable->m_pfn_qglRotatef; + qglScaled = NULL; + qglScalef = g_QglTable->m_pfn_qglScalef; + qglScissor = g_QglTable->m_pfn_qglScissor; + qglSelectBuffer = NULL; + qglShadeModel = g_QglTable->m_pfn_qglShadeModel; + 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 = g_QglTable->m_pfn_qglTexCoord2f; + qglTexCoord2fv = g_QglTable->m_pfn_qglTexCoord2fv; + 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 = g_QglTable->m_pfn_qglTexEnvf; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = g_QglTable->m_pfn_qglTexGenf; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = g_QglTable->m_pfn_qglTexImage1D; + qglTexImage2D = g_QglTable->m_pfn_qglTexImage2D; + qglTexParameterf = g_QglTable->m_pfn_qglTexParameterf; + qglTexParameterfv = g_QglTable->m_pfn_qglTexParameterfv; + qglTexParameteri = g_QglTable->m_pfn_qglTexParameteri; + qglTexParameteriv = g_QglTable->m_pfn_qglTexParameteriv; + qglTexSubImage1D = g_QglTable->m_pfn_qglTexSubImage1D; + qglTexSubImage2D = g_QglTable->m_pfn_qglTexSubImage2D; + qglTranslated = g_QglTable->m_pfn_qglTranslated; + qglTranslatef = g_QglTable->m_pfn_qglTranslatef; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = g_QglTable->m_pfn_qglVertex2f; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = g_QglTable->m_pfn_qglVertex3f; + qglVertex3fv = g_QglTable->m_pfn_qglVertex3fv; + 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 = g_QglTable->m_pfn_qglViewport; + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + qglColorTableEXT = NULL; + + qglMTexCoord2fSGIS = NULL; + qglSelectTextureSGIS = 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; +*/ +} + +#endif // _IGL_TO_QGL_H_ diff --git a/libs/l_net/l_net.c b/libs/l_net/l_net.c index fed856b5..9ead6652 100644 --- a/libs/l_net/l_net.c +++ b/libs/l_net/l_net.c @@ -1,627 +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 <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#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 index dd27d38b..167a5a36 100644 --- a/libs/l_net/l_net.h +++ b/libs/l_net/l_net.h @@ -1,125 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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_berkeley.c b/libs/l_net/l_net_berkeley.c index 60912aee..2d4d33bc 100644 --- a/libs/l_net/l_net_berkeley.c +++ b/libs/l_net/l_net_berkeley.c @@ -1,770 +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 <windows.h> -#include <unistd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "l_net.h" -#include "l_net_wins.h" - -#include <arpa/inet.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/ioctl.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <errno.h> -#include <netdb.h> -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "l_net.h" +#include "l_net_wins.h" + +#include <arpa/inet.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <errno.h> +#include <netdb.h> +#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 index 56ee6789..8a73f996 100644 --- a/libs/l_net/l_net_wins.c +++ b/libs/l_net/l_net_wins.c @@ -1,789 +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 <windows.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include "l_net.h" -#include "l_net_wins.h" -//#include <winsock.h> -//#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "l_net.h" +#include "l_net_wins.h" +//#include <winsock.h> +//#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 index 0a06ea7a..73598795 100644 --- a/libs/l_net/l_net_wins.h +++ b/libs/l_net/l_net_wins.h @@ -1,52 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 97fcf461..44bf01c9 100644 --- a/libs/mathlib.h +++ b/libs/mathlib.h @@ -1,305 +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 <math.h> - -#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__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <math.h> + +#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 index 510c4e7c..f421f917 100644 --- a/libs/mathlib/bbox.c +++ b/libs/mathlib/bbox.c @@ -1,391 +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 <float.h> - -#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; i<NUMDIM; i++) - { - if(origin[i] < (aabb->origin[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 -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <float.h> + +#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; i<NUMDIM; i++) + { + if(origin[i] < (aabb->origin[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 index bdef7145..7414c135 100644 --- a/libs/mathlib/linear.c +++ b/libs/mathlib/linear.c @@ -1,100 +1,100 @@ -#ifndef __APPLE__ -#include <malloc.h> -#else -#include <stdlib.h> -#endif -#include <limits.h> -#include <float.h> - -#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<n;i++) { - ip=indx[i]; - sum=b[ip]; - b[ip]=b[i]; - if (ii>=0) - for (j=ii;j<i;j++) sum -= a[i][j]*b[j]; - else if (sum) ii=i; - b[i]=sum; - } - for (i=n-1;i>=0;i--) { - sum=b[i]; - for (j=i+1;j<n;j++) sum -= a[i][j]*b[j]; - b[i]=sum/a[i][i]; - } -} -/* (C) Copr. 1986-92 Numerical Recipes Software */ - - -int ludcmp(float **a, int n, int *indx, float *d) -// given a matrix a[n][n] this routine replaces it with the LU decomposition of a rowwise -// permutation of itself. a and n are input. a is output, arranged as in above equation; -// indx[n] is an output vector that records the row permutation effected by the partial -// pivoting; d is output as +/-1 depending on whether the number of row interchanges was even -// or odd, respectively. This routine is used in combination with lubksb to solve linear -// equations or invert a matrix. -{ - int i,imax,j,k; - float big,dum,sum,temp; - float *vv; - - vv=(float*)malloc(sizeof(float)*n); - *d=1.0; - for (i=0;i<n;i++) { - big=0.0; - for (j=0;j<n;j++) - if ((temp=(float)fabs(a[i][j])) > big) big=temp; - if (big == 0.0) return 1; - vv[i]=1.0f/big; - } - for (j=0;j<n;j++) { - for (i=0;i<j;i++) { - sum=a[i][j]; - for (k=0;k<i;k++) sum -= a[i][k]*a[k][j]; - a[i][j]=sum; - } - big=0.0; - for (i=j;i<n;i++) { - sum=a[i][j]; - for (k=0;k<j;k++) - sum -= a[i][k]*a[k][j]; - a[i][j]=sum; - if ( (dum=vv[i]*(float)fabs(sum)) >= big) { - big=dum; - imax=i; - } - } - if (j != imax) { - for (k=0;k<n;k++) { - dum=a[imax][k]; - a[imax][k]=a[j][k]; - a[j][k]=dum; - } - *d = -(*d); - vv[imax]=vv[j]; - } - indx[j]=imax; - if (a[j][j] == 0.0) a[j][j]=TINY; - if (j != n) { - dum=1.0f/(a[j][j]); - for (i=j+1;i<n;i++) a[i][j] *= dum; - } - } - free(vv); - return 0; -} -/* (C) Copr. 1986-92 Numerical Recipes Software */ +#ifndef __APPLE__ +#include <malloc.h> +#else +#include <stdlib.h> +#endif +#include <limits.h> +#include <float.h> + +#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<n;i++) { + ip=indx[i]; + sum=b[ip]; + b[ip]=b[i]; + if (ii>=0) + for (j=ii;j<i;j++) sum -= a[i][j]*b[j]; + else if (sum) ii=i; + b[i]=sum; + } + for (i=n-1;i>=0;i--) { + sum=b[i]; + for (j=i+1;j<n;j++) sum -= a[i][j]*b[j]; + b[i]=sum/a[i][i]; + } +} +/* (C) Copr. 1986-92 Numerical Recipes Software */ + + +int ludcmp(float **a, int n, int *indx, float *d) +// given a matrix a[n][n] this routine replaces it with the LU decomposition of a rowwise +// permutation of itself. a and n are input. a is output, arranged as in above equation; +// indx[n] is an output vector that records the row permutation effected by the partial +// pivoting; d is output as +/-1 depending on whether the number of row interchanges was even +// or odd, respectively. This routine is used in combination with lubksb to solve linear +// equations or invert a matrix. +{ + int i,imax,j,k; + float big,dum,sum,temp; + float *vv; + + vv=(float*)malloc(sizeof(float)*n); + *d=1.0; + for (i=0;i<n;i++) { + big=0.0; + for (j=0;j<n;j++) + if ((temp=(float)fabs(a[i][j])) > big) big=temp; + if (big == 0.0) return 1; + vv[i]=1.0f/big; + } + for (j=0;j<n;j++) { + for (i=0;i<j;i++) { + sum=a[i][j]; + for (k=0;k<i;k++) sum -= a[i][k]*a[k][j]; + a[i][j]=sum; + } + big=0.0; + for (i=j;i<n;i++) { + sum=a[i][j]; + for (k=0;k<j;k++) + sum -= a[i][k]*a[k][j]; + a[i][j]=sum; + if ( (dum=vv[i]*(float)fabs(sum)) >= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=0;k<n;k++) { + dum=a[imax][k]; + a[imax][k]=a[j][k]; + a[j][k]=dum; + } + *d = -(*d); + vv[imax]=vv[j]; + } + indx[j]=imax; + if (a[j][j] == 0.0) a[j][j]=TINY; + if (j != n) { + dum=1.0f/(a[j][j]); + for (i=j+1;i<n;i++) a[i][j] *= dum; + } + } + free(vv); + return 0; +} +/* (C) Copr. 1986-92 Numerical Recipes Software */ diff --git a/libs/mathlib/m4x4.c b/libs/mathlib/m4x4.c index c1d01ee4..c2c64c53 100644 --- a/libs/mathlib/m4x4.c +++ b/libs/mathlib/m4x4.c @@ -1,790 +1,790 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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" -#include "memory.h" - -void m4x4_identity(m4x4_t matrix) -{ - matrix[1] = matrix[2] = matrix[3] = - matrix[4] = matrix[6] = matrix[7] = - matrix[8] = matrix[9] = matrix[11] = - matrix[12] = matrix[13] = matrix[14] = 0; - - matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; -} - -void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation) -{ - matrix[1] = matrix[2] = matrix[3] = - matrix[4] = matrix[6] = matrix[7] = - matrix[8] = matrix[9] = matrix[11] = 0; - - matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; - - matrix[12] = translation[0]; - matrix[13] = translation[1]; - matrix[14] = translation[2]; -} - -void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) -{ - double cx, sx, cy, sy, cz, sz; - - cx = cos(DEG2RAD(euler[0])); - sx = sin(DEG2RAD(euler[0])); - cy = cos(DEG2RAD(euler[1])); - sy = sin(DEG2RAD(euler[1])); - cz = cos(DEG2RAD(euler[2])); - sz = sin(DEG2RAD(euler[2])); - - switch(order) - { - case eXYZ: - -#if 1 - - { - matrix[0] = (vec_t)(cy*cz); - matrix[1] = (vec_t)(cy*sz); - matrix[2] = (vec_t)-sy; - matrix[4] = (vec_t)(sx*sy*cz + cx*-sz); - matrix[5] = (vec_t)(sx*sy*sz + cx*cz); - matrix[6] = (vec_t)(sx*cy); - matrix[8] = (vec_t)(cx*sy*cz + sx*sz); - matrix[9] = (vec_t)(cx*sy*sz + -sx*cz); - matrix[10] = (vec_t)(cx*cy); - } - - matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; - matrix[15] = 1; - -#else - - m4x4_identity(matrix); - matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; - matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; - - { - m4x4_t temp; - m4x4_identity(temp); - temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; - temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; - temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; - m4x4_premultiply_by_m4x4(matrix, temp); - } -#endif - - break; - - case eYZX: - m4x4_identity(matrix); - matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; - matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; - - { - m4x4_t temp; - m4x4_identity(temp); - temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; - temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; - temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; - m4x4_premultiply_by_m4x4(matrix, temp); - } - break; - - case eZXY: - m4x4_identity(matrix); - matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; - matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; - - { - m4x4_t temp; - m4x4_identity(temp); - temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; - temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; - temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; - m4x4_premultiply_by_m4x4(matrix, temp); - } - break; - - case eXZY: - m4x4_identity(matrix); - matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; - matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; - - { - m4x4_t temp; - m4x4_identity(temp); - temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; - temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; - temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; - m4x4_premultiply_by_m4x4(matrix, temp); - } - break; - - case eYXZ: - -/* transposed -| cy.cz + sx.sy.-sz + -cx.sy.0 0.cz + cx.-sz + sx.0 sy.cz + -sx.cy.-sz + cx.cy.0 | -| cy.sz + sx.sy.cz + -cx.sy.0 0.sz + cx.cz + sx.0 sy.sz + -sx.cy.cz + cx.cy.0 | -| cy.0 + sx.sy.0 + -cx.sy.1 0.0 + cx.0 + sx.1 sy.0 + -sx.cy.0 + cx.cy.1 | -*/ - -#if 1 - - { - matrix[0] = (vec_t)(cy*cz + sx*sy*-sz); - matrix[1] = (vec_t)(cy*sz + sx*sy*cz); - matrix[2] = (vec_t)(-cx*sy); - matrix[4] = (vec_t)(cx*-sz); - matrix[5] = (vec_t)(cx*cz); - matrix[6] = (vec_t)(sx); - matrix[8] = (vec_t)(sy*cz + -sx*cy*-sz); - matrix[9] = (vec_t)(sy*sz + -sx*cy*cz); - matrix[10] = (vec_t)(cx*cy); - } - - matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; - matrix[15] = 1; - -#else - - m4x4_identity(matrix); - matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; - matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; - - { - m4x4_t temp; - m4x4_identity(temp); - temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; - temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; - temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; - m4x4_premultiply_by_m4x4(matrix, temp); - } -#endif - break; - - case eZYX: -#if 1 - - { - matrix[0] = (vec_t)(cy*cz); - matrix[4] = (vec_t)(cy*-sz); - matrix[8] = (vec_t)sy; - matrix[1] = (vec_t)(sx*sy*cz + cx*sz); - matrix[5] = (vec_t)(sx*sy*-sz + cx*cz); - matrix[9] = (vec_t)(-sx*cy); - matrix[2] = (vec_t)(cx*-sy*cz + sx*sz); - matrix[6] = (vec_t)(cx*-sy*-sz + sx*cz); - matrix[10] = (vec_t)(cx*cy); - } - - matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; - matrix[15] = 1; - -#else - - m4x4_identity(matrix); - matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; - matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; - { - m4x4_t temp; - m4x4_identity(temp); - temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; - temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; - m4x4_premultiply_by_m4x4(matrix, temp); - m4x4_identity(temp); - temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; - temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; - m4x4_premultiply_by_m4x4(matrix, temp); - } - -#endif - break; - - } - -} - -void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale) -{ - matrix[1] = matrix[2] = matrix[3] = - matrix[4] = matrix[6] = matrix[7] = - matrix[8] = matrix[9] = matrix[11] = - matrix[12] = matrix[13] = matrix[14] = 0; - - matrix[15] = 1; - - matrix[0] = scale[0]; - matrix[5] = scale[1]; - matrix[10] = scale[2]; -} - -void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation) -{ - float xx,xy,xz,xw,yy,yz,yw,zz,zw; - - xx = rotation[0] * rotation[0]; - xy = rotation[0] * rotation[1]; - xz = rotation[0] * rotation[2]; - xw = rotation[0] * rotation[3]; - - yy = rotation[1] * rotation[1]; - yz = rotation[1] * rotation[2]; - yw = rotation[1] * rotation[3]; - - zz = rotation[2] * rotation[2]; - zw = rotation[2] * rotation[3]; - - matrix[0] = 1 - 2 * ( yy + zz ); - matrix[4] = 2 * ( xy - zw ); - matrix[8] = 2 * ( xz + yw ); - - matrix[1] = 2 * ( xy + zw ); - matrix[5] = 1 - 2 * ( xx + zz ); - matrix[9] = 2 * ( yz - xw ); - - matrix[2] = 2 * ( xz - yw ); - matrix[6] = 2 * ( yz + xw ); - matrix[10] = 1 - 2 * ( xx + yy ); - - matrix[3] = matrix[7] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0; - matrix[15] = 1; -} - -void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) -{ - vec4_t rotation; - angle *= 0.5; - - rotation[3] = (float)sin((float)(angle)); - - rotation[0] = axis[0] * rotation[3]; - rotation[1] = axis[1] * rotation[3]; - rotation[2] = axis[2] * rotation[3]; - rotation[3] = (float)cos((float)(angle)); - - m4x4_rotation_for_quat(matrix, rotation); -} - -void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation) -{ - m4x4_t temp; - m4x4_translation_for_vec3(temp, translation); - m4x4_multiply_by_m4x4(matrix, temp); -} - -void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) -{ - m4x4_t temp; - m4x4_rotation_for_vec3(temp, euler, order); - m4x4_multiply_by_m4x4(matrix, temp); -} - -void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale) -{ - m4x4_t temp; - m4x4_scale_for_vec3(temp, scale); - m4x4_multiply_by_m4x4(matrix, temp); -} - -void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation) -{ - m4x4_t temp; - m4x4_rotation_for_quat(temp, rotation); - m4x4_multiply_by_m4x4(matrix, temp); -} - -void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) -{ - m4x4_t temp; - m4x4_rotation_for_axisangle(temp, axis, angle); - m4x4_multiply_by_m4x4(matrix, temp); -} - -void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale) -{ - m4x4_translate_by_vec3(matrix, translation); - m4x4_rotate_by_vec3(matrix, euler, order); - m4x4_scale_by_vec3(matrix, scale); -} - -void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint) -{ - vec3_t vec3_temp; - VectorNegative(pivotpoint, vec3_temp); - - m4x4_translate_by_vec3(matrix, pivotpoint); - m4x4_rotate_by_vec3(matrix, euler, order); - m4x4_translate_by_vec3(matrix, vec3_temp); -} - -void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint) -{ - vec3_t vec3_temp; - VectorNegative(pivotpoint, vec3_temp); - - m4x4_translate_by_vec3(matrix, pivotpoint); - m4x4_scale_by_vec3(matrix, scale); - m4x4_translate_by_vec3(matrix, vec3_temp); -} - -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) -{ - vec3_t vec3_temp; - - VectorAdd(pivotpoint, translation, vec3_temp); - m4x4_translate_by_vec3(matrix, vec3_temp); - m4x4_rotate_by_vec3(matrix, euler, order); - m4x4_scale_by_vec3(matrix, scale); - VectorNegative(pivotpoint, vec3_temp); - m4x4_translate_by_vec3(matrix, vec3_temp); -} - -void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint) -{ - vec3_t vec3_temp; - VectorNegative(pivotpoint, vec3_temp); - - m4x4_translate_by_vec3(matrix, pivotpoint); - m4x4_rotate_by_quat(matrix, rotation); - m4x4_translate_by_vec3(matrix, vec3_temp); -} - -void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint) -{ - vec3_t vec3_temp; - VectorNegative(pivotpoint, vec3_temp); - - m4x4_translate_by_vec3(matrix, pivotpoint); - m4x4_rotate_by_axisangle(matrix, axis, angle); - m4x4_translate_by_vec3(matrix, vec3_temp); -} - - -/* -A = A.B - -A0 = B0 * A0 + B1 * A4 + B2 * A8 + B3 * A12 -A4 = B4 * A0 + B5 * A4 + B6 * A8 + B7 * A12 -A8 = B8 * A0 + B9 * A4 + B10* A8 + B11* A12 -A12= B12* A0 + B13* A4 + B14* A8 + B15* A12 - -A1 = B0 * A1 + B1 * A5 + B2 * A9 + B3 * A13 -A5 = B4 * A1 + B5 * A5 + B6 * A9 + B7 * A13 -A9 = B8 * A1 + B9 * A5 + B10* A9 + B11* A13 -A13= B12* A1 + B13* A5 + B14* A9 + B15* A13 - -A2 = B0 * A2 + B1 * A6 + B2 * A10+ B3 * A14 -A6 = B4 * A2 + B5 * A6 + B6 * A10+ B7 * A14 -A10= B8 * A2 + B9 * A6 + B10* A10+ B11* A14 -A14= B12* A2 + B13* A6 + B14* A10+ B15* A14 - -A3 = B0 * A3 + B1 * A7 + B2 * A11+ B3 * A15 -A7 = B4 * A3 + B5 * A7 + B6 * A11+ B7 * A15 -A11= B8 * A3 + B9 * A7 + B10* A11+ B11* A15 -A15= B12* A3 + B13* A7 + B14* A11+ B15* A15 -*/ - -void m4x4_multiply_by_m4x4(m4x4_t dst, const m4x4_t src) -{ - vec_t dst0, dst1, dst2, dst3; - -#if 1 - - dst0 = src[0] * dst[0] + src[1] * dst[4] + src[2] * dst[8] + src[3] * dst[12]; - dst1 = src[4] * dst[0] + src[5] * dst[4] + src[6] * dst[8] + src[7] * dst[12]; - dst2 = src[8] * dst[0] + src[9] * dst[4] + src[10]* dst[8] + src[11]* dst[12]; - dst3 = src[12]* dst[0] + src[13]* dst[4] + src[14]* dst[8] + src[15]* dst[12]; - dst[0] = dst0; dst[4] = dst1; dst[8] = dst2; dst[12]= dst3; - - dst0 = src[0] * dst[1] + src[1] * dst[5] + src[2] * dst[9] + src[3] * dst[13]; - dst1 = src[4] * dst[1] + src[5] * dst[5] + src[6] * dst[9] + src[7] * dst[13]; - dst2 = src[8] * dst[1] + src[9] * dst[5] + src[10]* dst[9] + src[11]* dst[13]; - dst3 = src[12]* dst[1] + src[13]* dst[5] + src[14]* dst[9] + src[15]* dst[13]; - dst[1] = dst0; dst[5] = dst1; dst[9] = dst2; dst[13]= dst3; - - dst0 = src[0] * dst[2] + src[1] * dst[6] + src[2] * dst[10]+ src[3] * dst[14]; - dst1 = src[4] * dst[2] + src[5] * dst[6] + src[6] * dst[10]+ src[7] * dst[14]; - dst2 = src[8] * dst[2] + src[9] * dst[6] + src[10]* dst[10]+ src[11]* dst[14]; - dst3 = src[12]* dst[2] + src[13]* dst[6] + src[14]* dst[10]+ src[15]* dst[14]; - dst[2] = dst0; dst[6] = dst1; dst[10]= dst2; dst[14]= dst3; - - dst0 = src[0] * dst[3] + src[1] * dst[7] + src[2] * dst[11]+ src[3] * dst[15]; - dst1 = src[4] * dst[3] + src[5] * dst[7] + src[6] * dst[11]+ src[7] * dst[15]; - dst2 = src[8] * dst[3] + src[9] * dst[7] + src[10]* dst[11]+ src[11]* dst[15]; - dst3 = src[12]* dst[3] + src[13]* dst[7] + src[14]* dst[11]+ src[15]* dst[15]; - dst[3] = dst0; dst[7] = dst1; dst[11]= dst2; dst[15]= dst3; - -#else - - vec_t * p = dst; - for(int i=0;i<4;i++) - { - dst1 = src[0] * p[0]; - dst1 += src[1] * p[4]; - dst1 += src[2] * p[8]; - dst1 += src[3] * p[12]; - dst2 = src[4] * p[0]; - dst2 += src[5] * p[4]; - dst2 += src[6] * p[8]; - dst2 += src[7] * p[12]; - dst3 = src[8] * p[0]; - dst3 += src[9] * p[4]; - dst3 += src[10] * p[8]; - dst3 += src[11] * p[12]; - dst4 = src[12] * p[0]; - dst4 += src[13] * p[4]; - dst4 += src[14] * p[8]; - dst4 += src[15] * p[12]; - - p[0] = dst1; - p[4] = dst2; - p[8] = dst3; - p[12] = dst4; - p++; - } - -#endif -} - -/* -A = B.A - -A0 = A0 * B0 + A1 * B4 + A2 * B8 + A3 * B12 -A1 = A0 * B1 + A1 * B5 + A2 * B9 + A3 * B13 -A2 = A0 * B2 + A1 * B6 + A2 * B10+ A3 * B14 -A3 = A0 * B3 + A1 * B7 + A2 * B11+ A3 * B15 - -A4 = A4 * B0 + A5 * B4 + A6 * B8 + A7 * B12 -A5 = A4 * B1 + A5 * B5 + A6 * B9 + A7 * B13 -A6 = A4 * B2 + A5 * B6 + A6 * B10+ A7 * B14 -A7 = A4 * B3 + A5 * B7 + A6 * B11+ A7 * B15 - -A8 = A8 * B0 + A9 * B4 + A10* B8 + A11* B12 -A9 = A8 * B1 + A9 * B5 + A10* B9 + A11* B13 -A10= A8 * B2 + A9 * B6 + A10* B10+ A11* B14 -A11= A8 * B3 + A9 * B7 + A10* B11+ A11* B15 - -A12= A12* B0 + A13* B4 + A14* B8 + A15* B12 -A13= A12* B1 + A13* B5 + A14* B9 + A15* B13 -A14= A12* B2 + A13* B6 + A14* B10+ A15* B14 -A15= A12* B3 + A13* B7 + A14* B11+ A15* B15 -*/ - -void m4x4_premultiply_by_m4x4(m4x4_t dst, const m4x4_t src) -{ - vec_t dst0, dst1, dst2, dst3; - -#if 1 - - dst0 = dst[0] * src[0] + dst[1] * src[4] + dst[2] * src[8] + dst[3] * src[12]; - dst1 = dst[0] * src[1] + dst[1] * src[5] + dst[2] * src[9] + dst[3] * src[13]; - dst2 = dst[0] * src[2] + dst[1] * src[6] + dst[2] * src[10]+ dst[3] * src[14]; - dst3 = dst[0] * src[3] + dst[1] * src[7] + dst[2] * src[11]+ dst[3] * src[15]; - dst[0] = dst0; dst[1] = dst1; dst[2] = dst2; dst[3]= dst3; - - dst0 = dst[4] * src[0] + dst[5] * src[4] + dst[6] * src[8] + dst[7] * src[12]; - dst1 = dst[4] * src[1] + dst[5] * src[5] + dst[6] * src[9] + dst[7] * src[13]; - dst2 = dst[4] * src[2] + dst[5] * src[6] + dst[6] * src[10]+ dst[7] * src[14]; - dst3 = dst[4] * src[3] + dst[5] * src[7] + dst[6] * src[11]+ dst[7] * src[15]; - dst[4] = dst0; dst[5] = dst1; dst[6] = dst2; dst[7]= dst3; - - dst0 = dst[8] * src[0] + dst[9] * src[4] + dst[10]* src[8] + dst[11]* src[12]; - dst1 = dst[8] * src[1] + dst[9] * src[5] + dst[10]* src[9] + dst[11]* src[13]; - dst2 = dst[8] * src[2] + dst[9] * src[6] + dst[10]* src[10]+ dst[11]* src[14]; - dst3 = dst[8] * src[3] + dst[9] * src[7] + dst[10]* src[11]+ dst[11]* src[15]; - dst[8] = dst0; dst[9] = dst1; dst[10] = dst2; dst[11]= dst3; - - dst0 = dst[12]* src[0] + dst[13]* src[4] + dst[14]* src[8] + dst[15]* src[12]; - dst1 = dst[12]* src[1] + dst[13]* src[5] + dst[14]* src[9] + dst[15]* src[13]; - dst2 = dst[12]* src[2] + dst[13]* src[6] + dst[14]* src[10]+ dst[15]* src[14]; - dst3 = dst[12]* src[3] + dst[13]* src[7] + dst[14]* src[11]+ dst[15]* src[15]; - dst[12] = dst0; dst[13] = dst1; dst[14] = dst2; dst[15]= dst3; - -#else - - vec_t* p = dst; - for(int i=0;i<4;i++) - { - dst1 = src[0] * p[0]; - dst2 = src[1] * p[0]; - dst3 = src[2] * p[0]; - dst4 = src[3] * p[0]; - dst1 += src[4] * p[1]; - dst2 += src[5] * p[1]; - dst3 += src[6] * p[1]; - dst4 += src[7] * p[1]; - dst1 += src[8] * p[2]; - dst2 += src[9] * p[2]; - dst4 += src[11] * p[2]; - dst3 += src[10] * p[2]; - dst1 += src[12] * p[3]; - dst2 += src[13] * p[3]; - dst3 += src[14] * p[3]; - dst4 += src[15] * p[3]; - - *p++ = dst1; - *p++ = dst2; - *p++ = dst3; - *p++ = dst4; - } - -#endif -} - -void m4x4_transform_point(const m4x4_t matrix, vec3_t point) -{ - float out1, out2, out3; - - out1 = matrix[0] * point[0]; - out2 = matrix[1] * point[0]; - out3 = matrix[2] * point[0]; - out1 += matrix[4] * point[1]; - out2 += matrix[5] * point[1]; - out3 += matrix[6] * point[1]; - out1 += matrix[8] * point[2]; - out2 += matrix[9] * point[2]; - out3 += matrix[10] * point[2]; - out1 += matrix[12]; - out2 += matrix[13]; - out3 += matrix[14]; - - point[0] = out1; - point[1] = out2; - point[2] = out3; -} - -void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal) -{ - float out1, out2, out3; - - out1 = matrix[0] * normal[0]; - out2 = matrix[1] * normal[0]; - out3 = matrix[2] * normal[0]; - out1 += matrix[4] * normal[1]; - out2 += matrix[5] * normal[1]; - out3 += matrix[6] * normal[1]; - out1 += matrix[8] * normal[2]; - out2 += matrix[9] * normal[2]; - out3 += matrix[10] * normal[2]; - - normal[0] = out1; - normal[1] = out2; - normal[2] = out3; -} - -void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector) -{ - float out1, out2, out3, out4; - - out1 = matrix[0] * vector[0]; - out2 = matrix[1] * vector[0]; - out3 = matrix[2] * vector[0]; - out4 = matrix[3] * vector[0]; - out1 += matrix[4] * vector[1]; - out2 += matrix[5] * vector[1]; - out3 += matrix[6] * vector[1]; - out4 += matrix[7] * vector[1]; - out1 += matrix[8] * vector[2]; - out2 += matrix[9] * vector[2]; - out3 += matrix[10] * vector[2]; - out4 += matrix[11] * vector[2]; - out1 += matrix[12] * vector[3]; - out2 += matrix[13] * vector[3]; - out3 += matrix[14] * vector[3]; - out4 += matrix[15] * vector[3]; - - vector[0] = out1; - vector[1] = out2; - vector[2] = out3; - vector[3] = out4; -} - -void m4x4_transpose(m4x4_t matrix) -{ - int i, j; - float temp, *p1, *p2; - - for (i=1; i<4; i++) { - for (j=0; j<i; j++) { - p1 = matrix+(j*4+i); - p2 = matrix+(i*4+j); - temp = *p1; - *p1=*p2; - *p2=temp; - } - } -} - -void m4x4_orthogonal_invert(m4x4_t matrix) -{ - float temp; - - temp = -matrix[3]; - matrix[3] = matrix[12]; - matrix[12] = temp; - - temp = -matrix[7]; - matrix[7] = matrix[13]; - matrix[13] = temp; - - temp = -matrix[11]; - matrix[11] = matrix[14]; - matrix[14] = temp; - - /* - temp = matrix[1]; - matrix[1] = matrix[4]; - matrix[4] = temp; - - temp = matrix[2]; - matrix[2] = matrix[8]; - matrix[8] = temp; - - temp = matrix[6]; - matrix[6] = matrix[9]; - matrix[9] = temp; - - matrix[3] = -matrix[3]; - matrix[7] = -matrix[7]; - matrix[11] = -matrix[11]; - */ -} - -float m3_det( m3x3_t mat ) -{ - float det; - - det = mat[0] * ( mat[4]*mat[8] - mat[7]*mat[5] ) - - mat[1] * ( mat[3]*mat[8] - mat[6]*mat[5] ) - + mat[2] * ( mat[3]*mat[7] - mat[6]*mat[4] ); - - return( det ); -} - -/* -void m3_inverse( m3x3_t mr, m3x3_t ma ) -{ - float det = m3_det( ma ); - - if ( fabs( det ) < 0.0005 ) - { - m3_identity( ma ); - return; - } - - mr[0] = ma[4]*ma[8] - ma[5]*ma[7] / det; - mr[1] = -( ma[1]*ma[8] - ma[7]*ma[2] ) / det; - mr[2] = ma[1]*ma[5] - ma[4]*ma[2] / det; - - mr[3] = -( ma[3]*ma[8] - ma[5]*ma[6] ) / det; - mr[4] = ma[0]*ma[8] - ma[6]*ma[2] / det; - mr[5] = -( ma[0]*ma[5] - ma[3]*ma[2] ) / det; - - mr[6] = ma[3]*ma[7] - ma[6]*ma[4] / det; - mr[7] = -( ma[0]*ma[7] - ma[6]*ma[1] ) / det; - mr[8] = ma[0]*ma[4] - ma[1]*ma[3] / det; -} -*/ - -void m4_submat( m4x4_t mr, m3x3_t mb, int i, int j ) -{ - int ti, tj, idst, jdst; - - for ( ti = 0; ti < 4; ti++ ) - { - if ( ti < i ) - idst = ti; - else - if ( ti > 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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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" +#include "memory.h" + +void m4x4_identity(m4x4_t matrix) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = + matrix[12] = matrix[13] = matrix[14] = 0; + + matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; +} + +void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = 0; + + matrix[0] = matrix[5] = matrix[10] = matrix[15] = 1; + + matrix[12] = translation[0]; + matrix[13] = translation[1]; + matrix[14] = translation[2]; +} + +void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) +{ + double cx, sx, cy, sy, cz, sz; + + cx = cos(DEG2RAD(euler[0])); + sx = sin(DEG2RAD(euler[0])); + cy = cos(DEG2RAD(euler[1])); + sy = sin(DEG2RAD(euler[1])); + cz = cos(DEG2RAD(euler[2])); + sz = sin(DEG2RAD(euler[2])); + + switch(order) + { + case eXYZ: + +#if 1 + + { + matrix[0] = (vec_t)(cy*cz); + matrix[1] = (vec_t)(cy*sz); + matrix[2] = (vec_t)-sy; + matrix[4] = (vec_t)(sx*sy*cz + cx*-sz); + matrix[5] = (vec_t)(sx*sy*sz + cx*cz); + matrix[6] = (vec_t)(sx*cy); + matrix[8] = (vec_t)(cx*sy*cz + sx*sz); + matrix[9] = (vec_t)(cx*sy*sz + -sx*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; + matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } +#endif + + break; + + case eYZX: + m4x4_identity(matrix); + matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; + matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eZXY: + m4x4_identity(matrix); + matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; + matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eXZY: + m4x4_identity(matrix); + matrix[5] =(vec_t) cx; matrix[6] =(vec_t) sx; + matrix[9] =(vec_t)-sx; matrix[10]=(vec_t) cx; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + } + break; + + case eYXZ: + +/* transposed +| cy.cz + sx.sy.-sz + -cx.sy.0 0.cz + cx.-sz + sx.0 sy.cz + -sx.cy.-sz + cx.cy.0 | +| cy.sz + sx.sy.cz + -cx.sy.0 0.sz + cx.cz + sx.0 sy.sz + -sx.cy.cz + cx.cy.0 | +| cy.0 + sx.sy.0 + -cx.sy.1 0.0 + cx.0 + sx.1 sy.0 + -sx.cy.0 + cx.cy.1 | +*/ + +#if 1 + + { + matrix[0] = (vec_t)(cy*cz + sx*sy*-sz); + matrix[1] = (vec_t)(cy*sz + sx*sy*cz); + matrix[2] = (vec_t)(-cx*sy); + matrix[4] = (vec_t)(cx*-sz); + matrix[5] = (vec_t)(cx*cz); + matrix[6] = (vec_t)(sx); + matrix[8] = (vec_t)(sy*cz + -sx*cy*-sz); + matrix[9] = (vec_t)(sy*sz + -sx*cy*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[0] =(vec_t) cy; matrix[2] =(vec_t)-sy; + matrix[8] =(vec_t) sy; matrix[10]=(vec_t) cy; + + { + m4x4_t temp; + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[0] =(vec_t) cz; temp[1] =(vec_t) sz; + temp[4] =(vec_t)-sz; temp[5] =(vec_t) cz; + m4x4_premultiply_by_m4x4(matrix, temp); + } +#endif + break; + + case eZYX: +#if 1 + + { + matrix[0] = (vec_t)(cy*cz); + matrix[4] = (vec_t)(cy*-sz); + matrix[8] = (vec_t)sy; + matrix[1] = (vec_t)(sx*sy*cz + cx*sz); + matrix[5] = (vec_t)(sx*sy*-sz + cx*cz); + matrix[9] = (vec_t)(-sx*cy); + matrix[2] = (vec_t)(cx*-sy*cz + sx*sz); + matrix[6] = (vec_t)(cx*-sy*-sz + sx*cz); + matrix[10] = (vec_t)(cx*cy); + } + + matrix[12] = matrix[13] = matrix[14] = matrix[3] = matrix[7] = matrix[11] = 0; + matrix[15] = 1; + +#else + + m4x4_identity(matrix); + matrix[0] =(vec_t) cz; matrix[1] =(vec_t) sz; + matrix[4] =(vec_t)-sz; matrix[5] =(vec_t) cz; + { + m4x4_t temp; + m4x4_identity(temp); + temp[0] =(vec_t) cy; temp[2] =(vec_t)-sy; + temp[8] =(vec_t) sy; temp[10]=(vec_t) cy; + m4x4_premultiply_by_m4x4(matrix, temp); + m4x4_identity(temp); + temp[5] =(vec_t) cx; temp[6] =(vec_t) sx; + temp[9] =(vec_t)-sx; temp[10]=(vec_t) cx; + m4x4_premultiply_by_m4x4(matrix, temp); + } + +#endif + break; + + } + +} + +void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale) +{ + matrix[1] = matrix[2] = matrix[3] = + matrix[4] = matrix[6] = matrix[7] = + matrix[8] = matrix[9] = matrix[11] = + matrix[12] = matrix[13] = matrix[14] = 0; + + matrix[15] = 1; + + matrix[0] = scale[0]; + matrix[5] = scale[1]; + matrix[10] = scale[2]; +} + +void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation) +{ + float xx,xy,xz,xw,yy,yz,yw,zz,zw; + + xx = rotation[0] * rotation[0]; + xy = rotation[0] * rotation[1]; + xz = rotation[0] * rotation[2]; + xw = rotation[0] * rotation[3]; + + yy = rotation[1] * rotation[1]; + yz = rotation[1] * rotation[2]; + yw = rotation[1] * rotation[3]; + + zz = rotation[2] * rotation[2]; + zw = rotation[2] * rotation[3]; + + matrix[0] = 1 - 2 * ( yy + zz ); + matrix[4] = 2 * ( xy - zw ); + matrix[8] = 2 * ( xz + yw ); + + matrix[1] = 2 * ( xy + zw ); + matrix[5] = 1 - 2 * ( xx + zz ); + matrix[9] = 2 * ( yz - xw ); + + matrix[2] = 2 * ( xz - yw ); + matrix[6] = 2 * ( yz + xw ); + matrix[10] = 1 - 2 * ( xx + yy ); + + matrix[3] = matrix[7] = matrix[11] = matrix[12] = matrix[13] = matrix[14] = 0; + matrix[15] = 1; +} + +void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) +{ + vec4_t rotation; + angle *= 0.5; + + rotation[3] = (float)sin((float)(angle)); + + rotation[0] = axis[0] * rotation[3]; + rotation[1] = axis[1] * rotation[3]; + rotation[2] = axis[2] * rotation[3]; + rotation[3] = (float)cos((float)(angle)); + + m4x4_rotation_for_quat(matrix, rotation); +} + +void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation) +{ + m4x4_t temp; + m4x4_translation_for_vec3(temp, translation); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order) +{ + m4x4_t temp; + m4x4_rotation_for_vec3(temp, euler, order); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale) +{ + m4x4_t temp; + m4x4_scale_for_vec3(temp, scale); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation) +{ + m4x4_t temp; + m4x4_rotation_for_quat(temp, rotation); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle) +{ + m4x4_t temp; + m4x4_rotation_for_axisangle(temp, axis, angle); + m4x4_multiply_by_m4x4(matrix, temp); +} + +void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale) +{ + m4x4_translate_by_vec3(matrix, translation); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_scale_by_vec3(matrix, scale); +} + +void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_scale_by_vec3(matrix, scale); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +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) +{ + vec3_t vec3_temp; + + VectorAdd(pivotpoint, translation, vec3_temp); + m4x4_translate_by_vec3(matrix, vec3_temp); + m4x4_rotate_by_vec3(matrix, euler, order); + m4x4_scale_by_vec3(matrix, scale); + VectorNegative(pivotpoint, vec3_temp); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_quat(matrix, rotation); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + +void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint) +{ + vec3_t vec3_temp; + VectorNegative(pivotpoint, vec3_temp); + + m4x4_translate_by_vec3(matrix, pivotpoint); + m4x4_rotate_by_axisangle(matrix, axis, angle); + m4x4_translate_by_vec3(matrix, vec3_temp); +} + + +/* +A = A.B + +A0 = B0 * A0 + B1 * A4 + B2 * A8 + B3 * A12 +A4 = B4 * A0 + B5 * A4 + B6 * A8 + B7 * A12 +A8 = B8 * A0 + B9 * A4 + B10* A8 + B11* A12 +A12= B12* A0 + B13* A4 + B14* A8 + B15* A12 + +A1 = B0 * A1 + B1 * A5 + B2 * A9 + B3 * A13 +A5 = B4 * A1 + B5 * A5 + B6 * A9 + B7 * A13 +A9 = B8 * A1 + B9 * A5 + B10* A9 + B11* A13 +A13= B12* A1 + B13* A5 + B14* A9 + B15* A13 + +A2 = B0 * A2 + B1 * A6 + B2 * A10+ B3 * A14 +A6 = B4 * A2 + B5 * A6 + B6 * A10+ B7 * A14 +A10= B8 * A2 + B9 * A6 + B10* A10+ B11* A14 +A14= B12* A2 + B13* A6 + B14* A10+ B15* A14 + +A3 = B0 * A3 + B1 * A7 + B2 * A11+ B3 * A15 +A7 = B4 * A3 + B5 * A7 + B6 * A11+ B7 * A15 +A11= B8 * A3 + B9 * A7 + B10* A11+ B11* A15 +A15= B12* A3 + B13* A7 + B14* A11+ B15* A15 +*/ + +void m4x4_multiply_by_m4x4(m4x4_t dst, const m4x4_t src) +{ + vec_t dst0, dst1, dst2, dst3; + +#if 1 + + dst0 = src[0] * dst[0] + src[1] * dst[4] + src[2] * dst[8] + src[3] * dst[12]; + dst1 = src[4] * dst[0] + src[5] * dst[4] + src[6] * dst[8] + src[7] * dst[12]; + dst2 = src[8] * dst[0] + src[9] * dst[4] + src[10]* dst[8] + src[11]* dst[12]; + dst3 = src[12]* dst[0] + src[13]* dst[4] + src[14]* dst[8] + src[15]* dst[12]; + dst[0] = dst0; dst[4] = dst1; dst[8] = dst2; dst[12]= dst3; + + dst0 = src[0] * dst[1] + src[1] * dst[5] + src[2] * dst[9] + src[3] * dst[13]; + dst1 = src[4] * dst[1] + src[5] * dst[5] + src[6] * dst[9] + src[7] * dst[13]; + dst2 = src[8] * dst[1] + src[9] * dst[5] + src[10]* dst[9] + src[11]* dst[13]; + dst3 = src[12]* dst[1] + src[13]* dst[5] + src[14]* dst[9] + src[15]* dst[13]; + dst[1] = dst0; dst[5] = dst1; dst[9] = dst2; dst[13]= dst3; + + dst0 = src[0] * dst[2] + src[1] * dst[6] + src[2] * dst[10]+ src[3] * dst[14]; + dst1 = src[4] * dst[2] + src[5] * dst[6] + src[6] * dst[10]+ src[7] * dst[14]; + dst2 = src[8] * dst[2] + src[9] * dst[6] + src[10]* dst[10]+ src[11]* dst[14]; + dst3 = src[12]* dst[2] + src[13]* dst[6] + src[14]* dst[10]+ src[15]* dst[14]; + dst[2] = dst0; dst[6] = dst1; dst[10]= dst2; dst[14]= dst3; + + dst0 = src[0] * dst[3] + src[1] * dst[7] + src[2] * dst[11]+ src[3] * dst[15]; + dst1 = src[4] * dst[3] + src[5] * dst[7] + src[6] * dst[11]+ src[7] * dst[15]; + dst2 = src[8] * dst[3] + src[9] * dst[7] + src[10]* dst[11]+ src[11]* dst[15]; + dst3 = src[12]* dst[3] + src[13]* dst[7] + src[14]* dst[11]+ src[15]* dst[15]; + dst[3] = dst0; dst[7] = dst1; dst[11]= dst2; dst[15]= dst3; + +#else + + vec_t * p = dst; + for(int i=0;i<4;i++) + { + dst1 = src[0] * p[0]; + dst1 += src[1] * p[4]; + dst1 += src[2] * p[8]; + dst1 += src[3] * p[12]; + dst2 = src[4] * p[0]; + dst2 += src[5] * p[4]; + dst2 += src[6] * p[8]; + dst2 += src[7] * p[12]; + dst3 = src[8] * p[0]; + dst3 += src[9] * p[4]; + dst3 += src[10] * p[8]; + dst3 += src[11] * p[12]; + dst4 = src[12] * p[0]; + dst4 += src[13] * p[4]; + dst4 += src[14] * p[8]; + dst4 += src[15] * p[12]; + + p[0] = dst1; + p[4] = dst2; + p[8] = dst3; + p[12] = dst4; + p++; + } + +#endif +} + +/* +A = B.A + +A0 = A0 * B0 + A1 * B4 + A2 * B8 + A3 * B12 +A1 = A0 * B1 + A1 * B5 + A2 * B9 + A3 * B13 +A2 = A0 * B2 + A1 * B6 + A2 * B10+ A3 * B14 +A3 = A0 * B3 + A1 * B7 + A2 * B11+ A3 * B15 + +A4 = A4 * B0 + A5 * B4 + A6 * B8 + A7 * B12 +A5 = A4 * B1 + A5 * B5 + A6 * B9 + A7 * B13 +A6 = A4 * B2 + A5 * B6 + A6 * B10+ A7 * B14 +A7 = A4 * B3 + A5 * B7 + A6 * B11+ A7 * B15 + +A8 = A8 * B0 + A9 * B4 + A10* B8 + A11* B12 +A9 = A8 * B1 + A9 * B5 + A10* B9 + A11* B13 +A10= A8 * B2 + A9 * B6 + A10* B10+ A11* B14 +A11= A8 * B3 + A9 * B7 + A10* B11+ A11* B15 + +A12= A12* B0 + A13* B4 + A14* B8 + A15* B12 +A13= A12* B1 + A13* B5 + A14* B9 + A15* B13 +A14= A12* B2 + A13* B6 + A14* B10+ A15* B14 +A15= A12* B3 + A13* B7 + A14* B11+ A15* B15 +*/ + +void m4x4_premultiply_by_m4x4(m4x4_t dst, const m4x4_t src) +{ + vec_t dst0, dst1, dst2, dst3; + +#if 1 + + dst0 = dst[0] * src[0] + dst[1] * src[4] + dst[2] * src[8] + dst[3] * src[12]; + dst1 = dst[0] * src[1] + dst[1] * src[5] + dst[2] * src[9] + dst[3] * src[13]; + dst2 = dst[0] * src[2] + dst[1] * src[6] + dst[2] * src[10]+ dst[3] * src[14]; + dst3 = dst[0] * src[3] + dst[1] * src[7] + dst[2] * src[11]+ dst[3] * src[15]; + dst[0] = dst0; dst[1] = dst1; dst[2] = dst2; dst[3]= dst3; + + dst0 = dst[4] * src[0] + dst[5] * src[4] + dst[6] * src[8] + dst[7] * src[12]; + dst1 = dst[4] * src[1] + dst[5] * src[5] + dst[6] * src[9] + dst[7] * src[13]; + dst2 = dst[4] * src[2] + dst[5] * src[6] + dst[6] * src[10]+ dst[7] * src[14]; + dst3 = dst[4] * src[3] + dst[5] * src[7] + dst[6] * src[11]+ dst[7] * src[15]; + dst[4] = dst0; dst[5] = dst1; dst[6] = dst2; dst[7]= dst3; + + dst0 = dst[8] * src[0] + dst[9] * src[4] + dst[10]* src[8] + dst[11]* src[12]; + dst1 = dst[8] * src[1] + dst[9] * src[5] + dst[10]* src[9] + dst[11]* src[13]; + dst2 = dst[8] * src[2] + dst[9] * src[6] + dst[10]* src[10]+ dst[11]* src[14]; + dst3 = dst[8] * src[3] + dst[9] * src[7] + dst[10]* src[11]+ dst[11]* src[15]; + dst[8] = dst0; dst[9] = dst1; dst[10] = dst2; dst[11]= dst3; + + dst0 = dst[12]* src[0] + dst[13]* src[4] + dst[14]* src[8] + dst[15]* src[12]; + dst1 = dst[12]* src[1] + dst[13]* src[5] + dst[14]* src[9] + dst[15]* src[13]; + dst2 = dst[12]* src[2] + dst[13]* src[6] + dst[14]* src[10]+ dst[15]* src[14]; + dst3 = dst[12]* src[3] + dst[13]* src[7] + dst[14]* src[11]+ dst[15]* src[15]; + dst[12] = dst0; dst[13] = dst1; dst[14] = dst2; dst[15]= dst3; + +#else + + vec_t* p = dst; + for(int i=0;i<4;i++) + { + dst1 = src[0] * p[0]; + dst2 = src[1] * p[0]; + dst3 = src[2] * p[0]; + dst4 = src[3] * p[0]; + dst1 += src[4] * p[1]; + dst2 += src[5] * p[1]; + dst3 += src[6] * p[1]; + dst4 += src[7] * p[1]; + dst1 += src[8] * p[2]; + dst2 += src[9] * p[2]; + dst4 += src[11] * p[2]; + dst3 += src[10] * p[2]; + dst1 += src[12] * p[3]; + dst2 += src[13] * p[3]; + dst3 += src[14] * p[3]; + dst4 += src[15] * p[3]; + + *p++ = dst1; + *p++ = dst2; + *p++ = dst3; + *p++ = dst4; + } + +#endif +} + +void m4x4_transform_point(const m4x4_t matrix, vec3_t point) +{ + float out1, out2, out3; + + out1 = matrix[0] * point[0]; + out2 = matrix[1] * point[0]; + out3 = matrix[2] * point[0]; + out1 += matrix[4] * point[1]; + out2 += matrix[5] * point[1]; + out3 += matrix[6] * point[1]; + out1 += matrix[8] * point[2]; + out2 += matrix[9] * point[2]; + out3 += matrix[10] * point[2]; + out1 += matrix[12]; + out2 += matrix[13]; + out3 += matrix[14]; + + point[0] = out1; + point[1] = out2; + point[2] = out3; +} + +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal) +{ + float out1, out2, out3; + + out1 = matrix[0] * normal[0]; + out2 = matrix[1] * normal[0]; + out3 = matrix[2] * normal[0]; + out1 += matrix[4] * normal[1]; + out2 += matrix[5] * normal[1]; + out3 += matrix[6] * normal[1]; + out1 += matrix[8] * normal[2]; + out2 += matrix[9] * normal[2]; + out3 += matrix[10] * normal[2]; + + normal[0] = out1; + normal[1] = out2; + normal[2] = out3; +} + +void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector) +{ + float out1, out2, out3, out4; + + out1 = matrix[0] * vector[0]; + out2 = matrix[1] * vector[0]; + out3 = matrix[2] * vector[0]; + out4 = matrix[3] * vector[0]; + out1 += matrix[4] * vector[1]; + out2 += matrix[5] * vector[1]; + out3 += matrix[6] * vector[1]; + out4 += matrix[7] * vector[1]; + out1 += matrix[8] * vector[2]; + out2 += matrix[9] * vector[2]; + out3 += matrix[10] * vector[2]; + out4 += matrix[11] * vector[2]; + out1 += matrix[12] * vector[3]; + out2 += matrix[13] * vector[3]; + out3 += matrix[14] * vector[3]; + out4 += matrix[15] * vector[3]; + + vector[0] = out1; + vector[1] = out2; + vector[2] = out3; + vector[3] = out4; +} + +void m4x4_transpose(m4x4_t matrix) +{ + int i, j; + float temp, *p1, *p2; + + for (i=1; i<4; i++) { + for (j=0; j<i; j++) { + p1 = matrix+(j*4+i); + p2 = matrix+(i*4+j); + temp = *p1; + *p1=*p2; + *p2=temp; + } + } +} + +void m4x4_orthogonal_invert(m4x4_t matrix) +{ + float temp; + + temp = -matrix[3]; + matrix[3] = matrix[12]; + matrix[12] = temp; + + temp = -matrix[7]; + matrix[7] = matrix[13]; + matrix[13] = temp; + + temp = -matrix[11]; + matrix[11] = matrix[14]; + matrix[14] = temp; + + /* + temp = matrix[1]; + matrix[1] = matrix[4]; + matrix[4] = temp; + + temp = matrix[2]; + matrix[2] = matrix[8]; + matrix[8] = temp; + + temp = matrix[6]; + matrix[6] = matrix[9]; + matrix[9] = temp; + + matrix[3] = -matrix[3]; + matrix[7] = -matrix[7]; + matrix[11] = -matrix[11]; + */ +} + +float m3_det( m3x3_t mat ) +{ + float det; + + det = mat[0] * ( mat[4]*mat[8] - mat[7]*mat[5] ) + - mat[1] * ( mat[3]*mat[8] - mat[6]*mat[5] ) + + mat[2] * ( mat[3]*mat[7] - mat[6]*mat[4] ); + + return( det ); +} + +/* +void m3_inverse( m3x3_t mr, m3x3_t ma ) +{ + float det = m3_det( ma ); + + if ( fabs( det ) < 0.0005 ) + { + m3_identity( ma ); + return; + } + + mr[0] = ma[4]*ma[8] - ma[5]*ma[7] / det; + mr[1] = -( ma[1]*ma[8] - ma[7]*ma[2] ) / det; + mr[2] = ma[1]*ma[5] - ma[4]*ma[2] / det; + + mr[3] = -( ma[3]*ma[8] - ma[5]*ma[6] ) / det; + mr[4] = ma[0]*ma[8] - ma[6]*ma[2] / det; + mr[5] = -( ma[0]*ma[5] - ma[3]*ma[2] ) / det; + + mr[6] = ma[3]*ma[7] - ma[6]*ma[4] / det; + mr[7] = -( ma[0]*ma[7] - ma[6]*ma[1] ) / det; + mr[8] = ma[0]*ma[4] - ma[1]*ma[3] / det; +} +*/ + +void m4_submat( m4x4_t mr, m3x3_t mb, int i, int j ) +{ + int ti, tj, idst, jdst; + + for ( ti = 0; ti < 4; ti++ ) + { + if ( ti < i ) + idst = ti; + else + if ( ti > 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 index 0c26a963..b9b7b869 100644 --- a/libs/mathlib/mathlib.c +++ b/libs/mathlib/mathlib.c @@ -1,593 +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 <memory.h> - -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]; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <memory.h> + +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/ray.c b/libs/mathlib/ray.c index 08cb9f87..cfe4bfd4 100644 --- a/libs/mathlib/ray.c +++ b/libs/mathlib/ray.c @@ -1,135 +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 <memory.h> - -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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <memory.h> + +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 index 32963357..d56f0263 100644 --- a/libs/md5lib.h +++ b/libs/md5lib.h @@ -1,91 +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 - <ghost@aladdin.com>. 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 <purschke@bnl.gov>. - 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 */ +/* + 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 + <ghost@aladdin.com>. 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 <purschke@bnl.gov>. + 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/md5lib.c b/libs/md5lib/md5lib.c index 6fb45f13..60b45148 100644 --- a/libs/md5lib/md5lib.c +++ b/libs/md5lib/md5lib.c @@ -1,395 +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 - <ghost@aladdin.com>. 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 <string.h> - 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 <stdio.h> 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 <string.h> - -/* 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)); -} +/* + 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 + <ghost@aladdin.com>. 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 <string.h> + 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 <stdio.h> 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 <string.h> + +/* 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/missing.h b/libs/missing.h index a9288d5c..f374d1ac 100644 --- a/libs/missing.h +++ b/libs/missing.h @@ -1,212 +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 <glib.h> -#include <string.h> - -#ifdef _WIN32 -#include <direct.h> -#include <io.h> - -#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_ +/* +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 <glib.h> +#include <string.h> + +#ifdef _WIN32 +#include <direct.h> +#include <io.h> + +#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 index 9a4e9ad7..638e353a 100644 --- a/libs/multimon.h +++ b/libs/multimon.h @@ -1,381 +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 - +#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/unzip.h b/libs/pak/unzip.h index d5c165dc..79a487e3 100644 --- a/libs/pak/unzip.h +++ b/libs/pak/unzip.h @@ -1,300 +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 -*/ + +#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 index 4c709cae..340e8798 100644 --- a/libs/pakstuff.h +++ b/libs/pakstuff.h @@ -1,150 +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 <windows.h> -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#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 index 8642527a..1912b4cb 100644 --- a/libs/picomodel.h +++ b/libs/picomodel.h @@ -1,345 +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 +/* ----------------------------------------------------------------------------- + +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 index 349222a4..8999f409 100644 --- a/libs/picomodel/lwo/clip.c +++ b/libs/picomodel/lwo/clip.c @@ -1,249 +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; -} +/* +====================================================================== +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 index 4ece5951..e3e281ff 100644 --- a/libs/picomodel/lwo/envelope.c +++ b/libs/picomodel/lwo/envelope.c @@ -1,600 +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; - } -} +/* +====================================================================== +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 index d07b0337..d337296c 100644 --- a/libs/picomodel/lwo/list.c +++ b/libs/picomodel/lwo/list.c @@ -1,101 +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; - } -} +/* +====================================================================== +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 index eea380bf..ec74932f 100644 --- a/libs/picomodel/lwo/lwio.c +++ b/libs/picomodel/lwo/lwio.c @@ -1,442 +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; -} +/* +====================================================================== +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 index 1d72af7d..f4c72443 100644 --- a/libs/picomodel/lwo/lwo2.c +++ b/libs/picomodel/lwo/lwo2.c @@ -1,308 +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; -} +/* +====================================================================== +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 index 1fe1dd97..1d55ba46 100644 --- a/libs/picomodel/lwo/lwo2.h +++ b/libs/picomodel/lwo/lwo2.h @@ -1,651 +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 +/* +====================================================================== +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 index 0e386a30..edf42cff 100644 --- a/libs/picomodel/lwo/lwob.c +++ b/libs/picomodel/lwo/lwob.c @@ -1,723 +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; -} +/* +====================================================================== +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 index d6c3152d..5cef01e6 100644 --- a/libs/picomodel/lwo/pntspols.c +++ b/libs/picomodel/lwo/pntspols.c @@ -1,537 +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; -} +/* +====================================================================== +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 index 6456a957..6c205df2 100644 --- a/libs/picomodel/lwo/surface.c +++ b/libs/picomodel/lwo/surface.c @@ -1,1004 +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; -} +/* +====================================================================== +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 index 44d317b0..eaa1e8fc 100644 --- a/libs/picomodel/lwo/vecmath.c +++ b/libs/picomodel/lwo/vecmath.c @@ -1,37 +1,37 @@ -/* -====================================================================== -vecmath.c - -Basic vector and matrix functions. - -Ernie Wright 17 Sep 00 -====================================================================== */ - -#include <math.h> - - -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; - } -} +/* +====================================================================== +vecmath.c + +Basic vector and matrix functions. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include <math.h> + + +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 index 1a24bee0..69f87cf9 100644 --- a/libs/picomodel/lwo/vmap.c +++ b/libs/picomodel/lwo/vmap.c @@ -1,243 +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; -} +/* +====================================================================== +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 index 6afae90a..3e32dd08 100644 --- a/libs/picomodel/picointernal.c +++ b/libs/picomodel/picointernal.c @@ -1,1353 +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 <string.h> -#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; pos<bufsize && pos<destsize; pos++) - { - if (buf[pos] == '\n') { pos++; break; } - dest[pos] = buf[pos]; - } - /* terminate dest and return */ - dest[pos] = '\0'; - return pos; -} - -/* _pico_parse_skip_white: - * skips white spaces in current pico parser, sets *hasLFs - * to 1 if linefeeds were skipped, and either returns the - * parser's cursor pointer or NULL on error. -sea - */ -void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ) -{ - /* sanity checks */ - if (p == NULL || p->cursor == 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; -} +/* ----------------------------------------------------------------------------- + +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 <string.h> +#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; pos<bufsize && pos<destsize; pos++) + { + if (buf[pos] == '\n') { pos++; break; } + dest[pos] = buf[pos]; + } + /* terminate dest and return */ + dest[pos] = '\0'; + return pos; +} + +/* _pico_parse_skip_white: + * skips white spaces in current pico parser, sets *hasLFs + * to 1 if linefeeds were skipped, and either returns the + * parser's cursor pointer or NULL on error. -sea + */ +void _pico_parse_skip_white( picoParser_t *p, int *hasLFs ) +{ + /* sanity checks */ + if (p == NULL || p->cursor == 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 index 37686ce1..8a3ee68d 100644 --- a/libs/picomodel/picointernal.h +++ b/libs/picomodel/picointernal.h @@ -1,205 +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 <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <ctype.h> -#include <math.h> - -#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 +/* ----------------------------------------------------------------------------- + +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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <math.h> + +#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 index ed4f8b21..d7790c37 100644 --- a/libs/picomodel/picomodel.c +++ b/libs/picomodel/picomodel.c @@ -1,1995 +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 <model>.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 ); - } -} +/* ----------------------------------------------------------------------------- + +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 <model>.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/picomodules.c b/libs/picomodel/picomodules.c index 060912f5..add477b5 100644 --- a/libs/picomodel/picomodules.c +++ b/libs/picomodel/picomodules.c @@ -1,92 +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; -} +/* ----------------------------------------------------------------------------- + +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 index 1ad95b1c..0f2b41f7 100644 --- a/libs/picomodel/pm_3ds.c +++ b/libs/picomodel/pm_3ds.c @@ -1,771 +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; i<max; i++) - { - if (debugChunkNames[i].id == id) - { - /* gaynux update -sea */ - return _pico_strlwr( debugChunkNames[i].name ); - } - } - return "chunk_unknown"; -} -#endif /*DEBUG_PM_3DS*/ - -/* this funky loader needs byte alignment */ -#pragma pack(push, 1) - -typedef struct S3dsIndices -{ - unsigned short a,b,c; - unsigned short visible; -} -T3dsIndices; - -typedef struct S3dsChunk -{ - unsigned short id; - unsigned int len; -} -T3dsChunk; - -/* restore previous data alignment */ -#pragma pack(pop) - -/* _3ds_canload: - * validates an autodesk 3ds model file. - */ -static int _3ds_canload( PM_PARAMS_CANLOAD ) -{ - T3dsChunk *chunk; - - /* to keep the compiler happy */ - *fileName = *fileName; - - /* sanity check */ - if (bufSize < sizeof(T3dsChunk)) - return PICO_PMV_ERROR_SIZE; - - /* get pointer to 3ds header chunk */ - chunk = (T3dsChunk *)buffer; - - /* check data length */ - if (bufSize < _pico_little_long(chunk->len)) - 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; i<numVerts; i++) - { - picoVec3_t v; - v[0] = GetFloat( pers ); - v[1] = GetFloat( pers ); /* ydnar: unflipped */ - v[2] = GetFloat( pers ); /* ydnar: unflipped and negated */ - - /* add current vertex */ - PicoSetSurfaceXYZ( pers->surface,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; i<numFaces; i++) - { - /* remember, we only need 3 of 4 values read in for each */ - /* face. the 4th value is a vis flag for 3dsmax which is */ - /* being ignored by us here */ - T3dsIndices face; - face.a = GetWord(pers); - face.c = GetWord(pers); /* ydnar: flipped order */ - face.b = GetWord(pers); /* ydnar: flipped order */ - face.visible = GetWord(pers); - - /* copy indexes */ - PicoSetSurfaceIndex( pers->surface, (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; i<numTexCoords; i++) - { - picoVec2_t uv; - uv[0] = GetFloat( pers ); - uv[1] = -GetFloat( pers ); /* ydnar: we use origin at bottom */ - - /* to make sure we don't mess up memory */ - if (pers->surface == 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; i<numSharedVerts; i++) - { - GetWord(pers); - } - /* success (no errors occured) */ - return 1; -} - -static int GetDiffuseColor (T3dsLoaderPers *pers) -{ - /* todo: support all 3ds specific color formats; */ - /* that means: rgb,tru,trug,rgbg */ - - /* get rgb color (range 0..255; 3 bytes) */ - picoColor_t color; - - color[0] = GetByte(pers); - color[1] = GetByte(pers); - color[2] = GetByte(pers); - color[3] = 255; - - /* store this as the current shader's diffuse color */ - if( pers->shader ) - { - 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 */ -}; +/* ----------------------------------------------------------------------------- + +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; i<max; i++) + { + if (debugChunkNames[i].id == id) + { + /* gaynux update -sea */ + return _pico_strlwr( debugChunkNames[i].name ); + } + } + return "chunk_unknown"; +} +#endif /*DEBUG_PM_3DS*/ + +/* this funky loader needs byte alignment */ +#pragma pack(push, 1) + +typedef struct S3dsIndices +{ + unsigned short a,b,c; + unsigned short visible; +} +T3dsIndices; + +typedef struct S3dsChunk +{ + unsigned short id; + unsigned int len; +} +T3dsChunk; + +/* restore previous data alignment */ +#pragma pack(pop) + +/* _3ds_canload: + * validates an autodesk 3ds model file. + */ +static int _3ds_canload( PM_PARAMS_CANLOAD ) +{ + T3dsChunk *chunk; + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if (bufSize < sizeof(T3dsChunk)) + return PICO_PMV_ERROR_SIZE; + + /* get pointer to 3ds header chunk */ + chunk = (T3dsChunk *)buffer; + + /* check data length */ + if (bufSize < _pico_little_long(chunk->len)) + 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; i<numVerts; i++) + { + picoVec3_t v; + v[0] = GetFloat( pers ); + v[1] = GetFloat( pers ); /* ydnar: unflipped */ + v[2] = GetFloat( pers ); /* ydnar: unflipped and negated */ + + /* add current vertex */ + PicoSetSurfaceXYZ( pers->surface,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; i<numFaces; i++) + { + /* remember, we only need 3 of 4 values read in for each */ + /* face. the 4th value is a vis flag for 3dsmax which is */ + /* being ignored by us here */ + T3dsIndices face; + face.a = GetWord(pers); + face.c = GetWord(pers); /* ydnar: flipped order */ + face.b = GetWord(pers); /* ydnar: flipped order */ + face.visible = GetWord(pers); + + /* copy indexes */ + PicoSetSurfaceIndex( pers->surface, (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; i<numTexCoords; i++) + { + picoVec2_t uv; + uv[0] = GetFloat( pers ); + uv[1] = -GetFloat( pers ); /* ydnar: we use origin at bottom */ + + /* to make sure we don't mess up memory */ + if (pers->surface == 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; i<numSharedVerts; i++) + { + GetWord(pers); + } + /* success (no errors occured) */ + return 1; +} + +static int GetDiffuseColor (T3dsLoaderPers *pers) +{ + /* todo: support all 3ds specific color formats; */ + /* that means: rgb,tru,trug,rgbg */ + + /* get rgb color (range 0..255; 3 bytes) */ + picoColor_t color; + + color[0] = GetByte(pers); + color[1] = GetByte(pers); + color[2] = GetByte(pers); + color[3] = 255; + + /* store this as the current shader's diffuse color */ + if( pers->shader ) + { + 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 index e8c5751d..ae5698df 100644 --- a/libs/picomodel/pm_ase.c +++ b/libs/picomodel/pm_ase.c @@ -1,1001 +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 */ -}; +/* ----------------------------------------------------------------------------- + +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 index c6f8e538..bb3216c3 100644 --- a/libs/picomodel/pm_fm.c +++ b/libs/picomodel/pm_fm.c @@ -1,670 +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; i<fm_head->numXYZ; 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; i<fm_head->numTris; 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; i<fm_head->numXYZ; 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; i<fm_head->numXYZ; 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; i<dup_index; i++) - _pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST); - - triangle = tri_verts; - for(i=0; i<fm_head->numTris; 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; i<dups; i++) - { - j = p_index_LUT_DUPS[i].OldVert; - /* set vertex origin */ - xyz[ 0 ] = frame->verts[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; i<fm_head->numXYZ; 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 */ -}; +/* ----------------------------------------------------------------------------- + +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; i<fm_head->numXYZ; 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; i<fm_head->numTris; 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; i<fm_head->numXYZ; 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; i<fm_head->numXYZ; 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; i<dup_index; i++) + _pico_printf( PICO_NORMAL, " Dup Index #%d OldVert: %d ST: %d\n", i, p_index_LUT_DUPS[i].OldVert, p_index_LUT_DUPS[i].ST); + + triangle = tri_verts; + for(i=0; i<fm_head->numTris; 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; i<dups; i++) + { + j = p_index_LUT_DUPS[i].OldVert; + /* set vertex origin */ + xyz[ 0 ] = frame->verts[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; i<fm_head->numXYZ; 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 index ce43d334..3fd5148e 100644 --- a/libs/picomodel/pm_fm.h +++ b/libs/picomodel/pm_fm.h @@ -1,367 +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 +/* ----------------------------------------------------------------------------- + +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 index ba83ceb5..d7b3bc8a 100644 --- a/libs/picomodel/pm_lwo.c +++ b/libs/picomodel/pm_lwo.c @@ -1,430 +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 */ -}; +/* ----------------------------------------------------------------------------- + +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 index 2351ea58..8a603a5d 100644 --- a/libs/picomodel/pm_md2.c +++ b/libs/picomodel/pm_md2.c @@ -1,670 +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; i<md2->numXYZ; 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; i<md2->numTris; 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; i<md2->numXYZ; 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; i<dups; i++) - { - j = p_index_LUT_DUPS[i].OldVert; - /* set vertex origin */ - xyz[ 0 ] = frame->verts[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; i<md2->numXYZ; 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 */ -}; +/* ----------------------------------------------------------------------------- + +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; i<md2->numXYZ; 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; i<md2->numTris; 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; i<md2->numXYZ; 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; i<dups; i++) + { + j = p_index_LUT_DUPS[i].OldVert; + /* set vertex origin */ + xyz[ 0 ] = frame->verts[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; i<md2->numXYZ; 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 index 6d87469d..55022b28 100644 --- a/libs/picomodel/pm_md3.c +++ b/libs/picomodel/pm_md3.c @@ -1,425 +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 */ -}; +/* ----------------------------------------------------------------------------- + +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 index 3036d112..27e612e8 100644 --- a/libs/picomodel/pm_mdc.c +++ b/libs/picomodel/pm_mdc.c @@ -1,750 +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 */ -}; +/* ----------------------------------------------------------------------------- + +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 index 4bbd9b38..27147bc0 100644 --- a/libs/picomodel/pm_ms3d.c +++ b/libs/picomodel/pm_ms3d.c @@ -1,494 +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; i<numVerts; i++) - { - TMsVertex *vertex; - vertex = (TMsVertex *)bufptr; - bufptr += sizeof( TMsVertex ); - - vertex->xyz[ 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; i<numTris; i++) - { - TMsTriangle *triangle; - triangle = (TMsTriangle *)bufptr; - bufptr += sizeof( TMsTriangle ); - - triangle->flags = _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<numGroups && i<MS3D_MAX_GROUPS; i++) - { - picoSurface_t *surface; - TMsGroup *group; - - group = (TMsGroup *)bufptr; - bufptr += sizeof( TMsGroup ); - - /* we ignore hidden groups */ - if (group->flags & MS3D_HIDDEN) - { - bufptr += (group->numTriangles * 2) + 1; - continue; - } - /* forced null term of group name */ - group->name[ 31 ] = '\0'; - - /* create new pico surface */ - surface = PicoNewSurface( model ); - if (surface == NULL) - { - PicoFreeModel( model ); - return NULL; - } - /* do surface setup */ - PicoSetSurfaceType( surface,PICO_TRIANGLES ); - PicoSetSurfaceName( surface,group->name ); - - /* process triangle indices */ - for (k=0; k<group->numTriangles; k++) - { - TMsTriangle *triangle; - unsigned int triangleIndex; - - /* get triangle index */ - bufptr = GetWord( bufptr,(int *)&triangleIndex ); - - /* get ptr to triangle data */ - triangle = (TMsTriangle *)(ptrToTris + (sizeof(TMsTriangle) * triangleIndex)); - - /* run through triangle vertices */ - for (m=0; m<3; m++) - { - TMsVertex *vertex; - unsigned int vertexIndex; - picoVec2_t texCoord; - - /* get ptr to vertex data */ - vertexIndex = triangle->vertexIndices[ m ]; - vertex = (TMsVertex *)(ptrToVerts + (sizeof(TMsVertex) * vertexIndex)); - - /* store vertex origin */ - PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz ); - - /* store vertex color */ - PicoSetSurfaceColor( surface,0,vertexIndex,white ); - - /* store vertex normal */ - PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] ); - - /* store current face vertex index */ - PicoSetSurfaceIndex( surface,(k * 3 + (2 - m)),(picoIndex_t)vertexIndex ); - - /* get texture vertex coord */ - texCoord[ 0 ] = triangle->s[ m ]; - texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */ - - /* store texture vertex coord */ - PicoSetSurfaceST( surface,0,vertexIndex,texCoord ); - } - } - /* store material */ - shaderRefs[ i ] = *bufptr++; - -#ifdef DEBUG_PM_MS3D - printf("Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles); -#endif - } - /* get number of materials */ - bufptr = GetWord( bufptr,&numMaterials ); - -#ifdef DEBUG_PM_MS3D - printf("NumMaterials: %d\n",numMaterials); -#endif - /* run through all materials in model */ - for (i=0; i<numMaterials; i++) - { - picoShader_t *shader; - picoColor_t ambient,diffuse,specular; - TMsMaterial *material; - int k; - - material = (TMsMaterial *)bufptr; - bufptr += sizeof( TMsMaterial ); - - /* null term strings */ - material->name [ 31 ] = '\0'; - material->texture [ 127 ] = '\0'; - material->alphamap[ 127 ] = '\0'; - - /* ltrim strings */ - _pico_strltrim( material->name ); - _pico_strltrim( material->texture ); - _pico_strltrim( material->alphamap ); - - /* rtrim strings */ - _pico_strrtrim( material->name ); - _pico_strrtrim( material->texture ); - _pico_strrtrim( material->alphamap ); - - /* create new pico shader */ - shader = PicoNewShader( model ); - if (shader == NULL) - { - PicoFreeModel( model ); - return NULL; - } - /* scale shader colors */ - for (k=0; k<4; k++) - { - ambient [ k ] = (picoByte_t) (material->ambient[ k ] * 255); - diffuse [ k ] = (picoByte_t) (material->diffuse[ k ] * 255); - specular[ k ] = (picoByte_t) (material->specular[ k ] * 255); - } - /* set shader colors */ - PicoSetShaderAmbientColor( shader,ambient ); - PicoSetShaderDiffuseColor( shader,diffuse ); - PicoSetShaderSpecularColor( shader,specular ); - - /* set shader transparency */ - PicoSetShaderTransparency( shader,material->transparency ); - - /* set shader shininess (0..127) */ - PicoSetShaderShininess( shader,material->shininess ); - - /* set shader name */ - PicoSetShaderName( shader,material->name ); - - /* set shader texture map name */ - PicoSetShaderMapName( shader,material->texture ); - -#ifdef DEBUG_PM_MS3D - printf("Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap); -#endif - } - /* assign shaders to surfaces */ - for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++) - { - picoSurface_t *surface; - picoShader_t *shader; - - /* sanity check */ - if (shaderRefs[ i ] >= MS3D_MAX_MATERIALS || - shaderRefs[ i ] < 0) - continue; - - /* get surface */ - surface = PicoGetModelSurface( model,i ); - if (surface == NULL) continue; - - /* get shader */ - shader = PicoGetModelShader( model,shaderRefs[ i ] ); - if (shader == NULL) continue; - - /* assign shader */ - PicoSetSurfaceShader( surface,shader ); - -#ifdef DEBUG_PM_MS3D - printf("Mapped: %d ('%s') to %d (%s)\n", - shaderRefs[i],shader->name,i,surface->name); -#endif - } - /* return allocated pico model */ - return model; -// return NULL; -} - -/* pico file format module definition */ -const picoModule_t picoModuleMS3D = -{ - "0.4-a", /* module version string */ - "Milkshape 3D", /* module display name */ - "seaw0lf", /* author's name */ - "2002 seaw0lf", /* module copyright */ - { - "ms3d",NULL,NULL,NULL /* default extensions to use */ - }, - _ms3d_canload, /* validation routine */ - _ms3d_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +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; i<numVerts; i++) + { + TMsVertex *vertex; + vertex = (TMsVertex *)bufptr; + bufptr += sizeof( TMsVertex ); + + vertex->xyz[ 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; i<numTris; i++) + { + TMsTriangle *triangle; + triangle = (TMsTriangle *)bufptr; + bufptr += sizeof( TMsTriangle ); + + triangle->flags = _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<numGroups && i<MS3D_MAX_GROUPS; i++) + { + picoSurface_t *surface; + TMsGroup *group; + + group = (TMsGroup *)bufptr; + bufptr += sizeof( TMsGroup ); + + /* we ignore hidden groups */ + if (group->flags & MS3D_HIDDEN) + { + bufptr += (group->numTriangles * 2) + 1; + continue; + } + /* forced null term of group name */ + group->name[ 31 ] = '\0'; + + /* create new pico surface */ + surface = PicoNewSurface( model ); + if (surface == NULL) + { + PicoFreeModel( model ); + return NULL; + } + /* do surface setup */ + PicoSetSurfaceType( surface,PICO_TRIANGLES ); + PicoSetSurfaceName( surface,group->name ); + + /* process triangle indices */ + for (k=0; k<group->numTriangles; k++) + { + TMsTriangle *triangle; + unsigned int triangleIndex; + + /* get triangle index */ + bufptr = GetWord( bufptr,(int *)&triangleIndex ); + + /* get ptr to triangle data */ + triangle = (TMsTriangle *)(ptrToTris + (sizeof(TMsTriangle) * triangleIndex)); + + /* run through triangle vertices */ + for (m=0; m<3; m++) + { + TMsVertex *vertex; + unsigned int vertexIndex; + picoVec2_t texCoord; + + /* get ptr to vertex data */ + vertexIndex = triangle->vertexIndices[ m ]; + vertex = (TMsVertex *)(ptrToVerts + (sizeof(TMsVertex) * vertexIndex)); + + /* store vertex origin */ + PicoSetSurfaceXYZ( surface,vertexIndex,vertex->xyz ); + + /* store vertex color */ + PicoSetSurfaceColor( surface,0,vertexIndex,white ); + + /* store vertex normal */ + PicoSetSurfaceNormal( surface,vertexIndex,triangle->vertexNormals[ m ] ); + + /* store current face vertex index */ + PicoSetSurfaceIndex( surface,(k * 3 + (2 - m)),(picoIndex_t)vertexIndex ); + + /* get texture vertex coord */ + texCoord[ 0 ] = triangle->s[ m ]; + texCoord[ 1 ] = -triangle->t[ m ]; /* flip t */ + + /* store texture vertex coord */ + PicoSetSurfaceST( surface,0,vertexIndex,texCoord ); + } + } + /* store material */ + shaderRefs[ i ] = *bufptr++; + +#ifdef DEBUG_PM_MS3D + printf("Group %d: '%s' (%d tris)\n",i,group->name,group->numTriangles); +#endif + } + /* get number of materials */ + bufptr = GetWord( bufptr,&numMaterials ); + +#ifdef DEBUG_PM_MS3D + printf("NumMaterials: %d\n",numMaterials); +#endif + /* run through all materials in model */ + for (i=0; i<numMaterials; i++) + { + picoShader_t *shader; + picoColor_t ambient,diffuse,specular; + TMsMaterial *material; + int k; + + material = (TMsMaterial *)bufptr; + bufptr += sizeof( TMsMaterial ); + + /* null term strings */ + material->name [ 31 ] = '\0'; + material->texture [ 127 ] = '\0'; + material->alphamap[ 127 ] = '\0'; + + /* ltrim strings */ + _pico_strltrim( material->name ); + _pico_strltrim( material->texture ); + _pico_strltrim( material->alphamap ); + + /* rtrim strings */ + _pico_strrtrim( material->name ); + _pico_strrtrim( material->texture ); + _pico_strrtrim( material->alphamap ); + + /* create new pico shader */ + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + /* scale shader colors */ + for (k=0; k<4; k++) + { + ambient [ k ] = (picoByte_t) (material->ambient[ k ] * 255); + diffuse [ k ] = (picoByte_t) (material->diffuse[ k ] * 255); + specular[ k ] = (picoByte_t) (material->specular[ k ] * 255); + } + /* set shader colors */ + PicoSetShaderAmbientColor( shader,ambient ); + PicoSetShaderDiffuseColor( shader,diffuse ); + PicoSetShaderSpecularColor( shader,specular ); + + /* set shader transparency */ + PicoSetShaderTransparency( shader,material->transparency ); + + /* set shader shininess (0..127) */ + PicoSetShaderShininess( shader,material->shininess ); + + /* set shader name */ + PicoSetShaderName( shader,material->name ); + + /* set shader texture map name */ + PicoSetShaderMapName( shader,material->texture ); + +#ifdef DEBUG_PM_MS3D + printf("Material %d: '%s' ('%s','%s')\n",i,material->name,material->texture,material->alphamap); +#endif + } + /* assign shaders to surfaces */ + for (i=0; i<numGroups && i<MS3D_MAX_GROUPS; i++) + { + picoSurface_t *surface; + picoShader_t *shader; + + /* sanity check */ + if (shaderRefs[ i ] >= MS3D_MAX_MATERIALS || + shaderRefs[ i ] < 0) + continue; + + /* get surface */ + surface = PicoGetModelSurface( model,i ); + if (surface == NULL) continue; + + /* get shader */ + shader = PicoGetModelShader( model,shaderRefs[ i ] ); + if (shader == NULL) continue; + + /* assign shader */ + PicoSetSurfaceShader( surface,shader ); + +#ifdef DEBUG_PM_MS3D + printf("Mapped: %d ('%s') to %d (%s)\n", + shaderRefs[i],shader->name,i,surface->name); +#endif + } + /* return allocated pico model */ + return model; +// return NULL; +} + +/* pico file format module definition */ +const picoModule_t picoModuleMS3D = +{ + "0.4-a", /* module version string */ + "Milkshape 3D", /* module display name */ + "seaw0lf", /* author's name */ + "2002 seaw0lf", /* module copyright */ + { + "ms3d",NULL,NULL,NULL /* default extensions to use */ + }, + _ms3d_canload, /* validation routine */ + _ms3d_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_obj.c b/libs/picomodel/pm_obj.c index 2dc27e1d..6cb40668 100644 --- a/libs/picomodel/pm_obj.c +++ b/libs/picomodel/pm_obj.c @@ -1,858 +1,858 @@ -/* ----------------------------------------------------------------------------- - -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_OBJ_C - -/* dependencies */ -#include "picointernal.h" - -/* disable warnings */ -#ifdef _WIN32 -#pragma warning( disable:4100 ) /* unref param */ -#endif - -/* todo: - * - '_obj_load' code crashes in a weird way after - * '_obj_mtl_load' for a few .mtl files - * - process 'mtllib' rather than using <model>.mtl - * - handle 'usemtl' statements - */ -/* uncomment when debugging this module */ -/* #define DEBUG_PM_OBJ */ -/* #define DEBUG_PM_OBJ_EX */ - -/* this holds temporary vertex data read by parser */ -typedef struct SObjVertexData -{ - picoVec3_t v; /* geometric vertices */ - picoVec2_t vt; /* texture vertices */ - picoVec3_t vn; /* vertex normals (optional) */ -} -TObjVertexData; - -/* _obj_canload: - * validates a wavefront obj model file. - */ -static int _obj_canload( PM_PARAMS_CANLOAD ) -{ - picoParser_t *p; - - /* check data length */ - if (bufSize < 30) - return PICO_PMV_ERROR_SIZE; - - /* first check file extension. we have to do this for objs */ - /* cause there is no good way to identify the contents */ - if (_pico_stristr(fileName,".obj") != NULL || - _pico_stristr(fileName,".wf" ) != NULL) - { - return PICO_PMV_OK; - } - /* if the extension check failed we parse through the first */ - /* few lines in file and look for common keywords often */ - /* appearing at the beginning of wavefront objects */ - - /* alllocate a new pico parser */ - p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); - if (p == NULL) - return PICO_PMV_ERROR_MEMORY; - - /* parse obj head line by line for type check */ - while( 1 ) - { - /* get first token on line */ - if (_pico_parse_first( p ) == NULL) - break; - - /* we only parse the first few lines, say 80 */ - if (p->curLine > 80) - break; - - /* skip empty lines */ - if (p->token == NULL || !strlen( p->token )) - continue; - - /* material library keywords are teh good */ - if (!_pico_stricmp(p->token,"usemtl") || - !_pico_stricmp(p->token,"mtllib") || - !_pico_stricmp(p->token,"g") || - !_pico_stricmp(p->token,"v")) /* v,g bit fishy, but uh... */ - { - /* free the pico parser thing */ - _pico_free_parser( p ); - - /* seems to be a valid wavefront obj */ - return PICO_PMV_OK; - } - /* skip rest of line */ - _pico_parse_skip_rest( p ); - } - /* free the pico parser thing */ - _pico_free_parser( p ); - - /* doesn't really look like an obj to us */ - return PICO_PMV_ERROR; -} - -/* SizeObjVertexData: - * This pretty piece of 'alloc ahead' code dynamically - * allocates - and reallocates as soon as required - - * my vertex data array in even steps. - */ -#define SIZE_OBJ_STEP 4096 - -static TObjVertexData *SizeObjVertexData( - TObjVertexData *vertexData, int reqEntries, - int *entries, int *allocated) -{ - int newAllocated; - - /* sanity checks */ - if (reqEntries < 1) - return NULL; - if (entries == NULL || allocated == NULL) - return NULL; /* must have */ - - /* no need to grow yet */ - if (vertexData && (reqEntries < *allocated)) - { - *entries = reqEntries; - return vertexData; - } - /* given vertex data ptr not allocated yet */ - if (vertexData == NULL) - { - /* how many entries to allocate */ - newAllocated = (reqEntries > SIZE_OBJ_STEP) ? - reqEntries : SIZE_OBJ_STEP; - - /* throw out an extended debug message */ -#ifdef DEBUG_PM_OBJ_EX - printf("SizeObjVertexData: allocate (%d entries)\n", - newAllocated); -#endif - /* first time allocation */ - vertexData = (TObjVertexData *) - _pico_alloc( sizeof(TObjVertexData) * newAllocated ); - - /* allocation failed */ - if (vertexData == NULL) - return NULL; - - /* allocation succeeded */ - *allocated = newAllocated; - *entries = reqEntries; - return vertexData; - } - /* given vertex data ptr needs to be resized */ - if (reqEntries == *allocated) - { - newAllocated = (*allocated + SIZE_OBJ_STEP); - - /* throw out an extended debug message */ -#ifdef DEBUG_PM_OBJ_EX - printf("SizeObjVertexData: reallocate (%d entries)\n", - newAllocated); -#endif - /* try to reallocate */ - vertexData = (TObjVertexData *) - _pico_realloc( (void *)&vertexData, - sizeof(TObjVertexData) * (*allocated), - sizeof(TObjVertexData) * (newAllocated)); - - /* reallocation failed */ - if (vertexData == NULL) - return NULL; - - /* reallocation succeeded */ - *allocated = newAllocated; - *entries = reqEntries; - return vertexData; - } - /* we're b0rked when we reach this */ - return NULL; -} - -static void FreeObjVertexData( TObjVertexData *vertexData ) -{ - if (vertexData != NULL) - { - free( (TObjVertexData *)vertexData ); - } -} - -static int _obj_mtl_load( picoModel_t *model ) -{ - picoShader_t *curShader = NULL; - picoParser_t *p; - picoByte_t *mtlBuffer; - int mtlBufSize; - char *fileName; - - /* sanity checks */ - if( model == NULL || model->fileName == NULL ) - return 0; - - /* skip if we have a zero length model file name */ - if (!strlen( model->fileName )) - return 0; - - /* helper */ - #define _obj_mtl_error_return \ - { \ - _pico_free_parser( p ); \ - _pico_free_file( mtlBuffer ); \ - _pico_free( fileName ); \ - return 0; \ - } - /* alloc copy of model file name */ - fileName = _pico_clone_alloc( model->fileName,-1 ); - if (fileName == NULL) - return 0; - - /* change extension of model file to .mtl */ - _pico_setfext( fileName, "mtl" ); - - /* load .mtl file contents */ - _pico_load_file( fileName,&mtlBuffer,&mtlBufSize ); - - /* check result */ - if (mtlBufSize == 0) return 1; /* file is empty: no error */ - if (mtlBufSize < 0) return 0; /* load failed: error */ - - /* create a new pico parser */ - p = _pico_new_parser( mtlBuffer, mtlBufSize ); - if (p == NULL) - _obj_mtl_error_return; - - /* doo teh .mtl parse */ - while( 1 ) - { - /* get next token in material file */ - if (_pico_parse( p,1 ) == NULL) - break; -#if 0 - - /* skip empty lines */ - if (p->token == NULL || !strlen( p->token )) - continue; - - /* skip comment lines */ - if (p->token[0] == '#') - { - _pico_parse_skip_rest( p ); - continue; - } - /* new material */ - if (!_pico_stricmp(p->token,"newmtl")) - { - picoShader_t *shader; - char *name; - - /* get material name */ - name = _pico_parse( p,0 ); - - /* validate material name */ - if (name == NULL || !strlen(name)) - { - _pico_printf( PICO_ERROR,"Missing material name in MTL, line %d.",p->curLine); - _obj_mtl_error_return; - } - /* create a new pico shader */ - shader = PicoNewShader( model ); - if (shader == NULL) - _obj_mtl_error_return; - - /* set shader name */ - PicoSetShaderName( shader,name ); - - /* assign pointer to current shader */ - curShader = shader; - } - /* diffuse map name */ - else if (!_pico_stricmp(p->token,"map_kd")) - { - char *mapName; - - /* pointer to current shader must be valid */ - if (curShader == NULL) - _obj_mtl_error_return; - - /* get material's diffuse map name */ - mapName = _pico_parse( p,0 ); - - /* validate map name */ - if (mapName == NULL || !strlen(mapName)) - { - _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine); - _obj_mtl_error_return; - } - /* set shader map name */ - PicoSetShaderMapName( shader,mapName ); - } - /* dissolve factor (pseudo transparency 0..1) */ - /* where 0 means 100% transparent and 1 means opaque */ - else if (!_pico_stricmp(p->token,"d")) - { - picoByte_t *diffuse; - float value; - - - /* get dissolve factor */ - if (!_pico_parse_float( p,&value )) - _obj_mtl_error_return; - - /* set shader transparency */ - PicoSetShaderTransparency( curShader,value ); - - /* get shader's diffuse color */ - diffuse = PicoGetShaderDiffuseColor( curShader ); - - /* set diffuse alpha to transparency */ - diffuse[ 3 ] = (picoByte_t)( value * 255.0 ); - - /* set shader's new diffuse color */ - PicoSetShaderDiffuseColor( curShader,diffuse ); - } - /* shininess (phong specular component) */ - else if (!_pico_stricmp(p->token,"ns")) - { - /* remark: - * - well, this is some major obj spec fuckup once again. some - * apps store this in 0..1 range, others use 0..100 range, - * even others use 0..2048 range, and again others use the - * range 0..128, some even use 0..1000, 0..200, 400..700, - * honestly, what's up with the 3d app coders? happens when - * you smoke too much weed i guess. -sea - */ - float value; - - /* pointer to current shader must be valid */ - if (curShader == NULL) - _obj_mtl_error_return; - - /* get totally screwed up shininess (a random value in fact ;) */ - if (!_pico_parse_float( p,&value )) - _obj_mtl_error_return; - - /* okay, there is no way to set this correctly, so we simply */ - /* try to guess a few ranges (most common ones i have seen) */ - - /* assume 0..2048 range */ - if (value > 1000) - value = 128.0 * (value / 2048.0); - /* assume 0..1000 range */ - else if (value > 200) - value = 128.0 * (value / 1000.0); - /* assume 0..200 range */ - else if (value > 100) - value = 128.0 * (value / 200.0); - /* assume 0..100 range */ - else if (value > 1) - value = 128.0 * (value / 100.0); - /* assume 0..1 range */ - else { - value *= 128.0; - } - /* negative shininess is bad (yes, i have seen it...) */ - if (value < 0.0) value = 0.0; - - /* set the pico shininess value in range 0..127 */ - /* geez, .obj is such a mess... */ - PicoSetShaderShininess( curShader,value ); - } - /* kol0r ambient (wut teh fuk does "ka" stand for?) */ - else if (!_pico_stricmp(p->token,"ka")) - { - picoColor_t color; - picoVec3_t v; - - /* pointer to current shader must be valid */ - if (curShader == NULL) - _obj_mtl_error_return; - - /* get color vector */ - if (!_pico_parse_vec( p,v )) - _obj_mtl_error_return; - - /* scale to byte range */ - color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); - color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); - color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); - color[ 3 ] = (picoByte_t)( 255 ); - - /* set ambient color */ - PicoSetShaderAmbientColor( curShader,color ); - } - /* kol0r diffuse */ - else if (!_pico_stricmp(p->token,"kd")) - { - picoColor_t color; - picoVec3_t v; - - /* pointer to current shader must be valid */ - if (curShader == NULL) - _obj_mtl_error_return; - - /* get color vector */ - if (!_pico_parse_vec( p,v )) - _obj_mtl_error_return; - - /* scale to byte range */ - color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); - color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); - color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); - color[ 3 ] = (picoByte_t)( 255 ); - - /* set diffuse color */ - PicoSetShaderDiffuseColor( curShader,color ); - } - /* kol0r specular */ - else if (!_pico_stricmp(p->token,"ks")) - { - picoColor_t color; - picoVec3_t v; - - /* pointer to current shader must be valid */ - if (curShader == NULL) - _obj_mtl_error_return; - - /* get color vector */ - if (!_pico_parse_vec( p,v )) - _obj_mtl_error_return; - - /* scale to byte range */ - color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); - color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); - color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); - color[ 3 ] = (picoByte_t)( 255 ); - - /* set specular color */ - PicoSetShaderSpecularColor( curShader,color ); - } -#endif - /* skip rest of line */ - _pico_parse_skip_rest( p ); - } - - /* free parser, file buffer, and file name */ - _pico_free_parser( p ); - _pico_free_file( mtlBuffer ); - _pico_free( fileName ); - - /* return with success */ - return 1; -} - -/* _obj_load: - * loads a wavefront obj model file. -*/ -static picoModel_t *_obj_load( PM_PARAMS_LOAD ) -{ - TObjVertexData *vertexData = NULL; - picoModel_t *model; - picoSurface_t *curSurface = NULL; - picoParser_t *p; - int allocated; - int entries; - int numVerts = 0; - int numNormals = 0; - int numUVs = 0; - int curVertex = 0; - int curFace = 0; - - /* helper */ - #define _obj_error_return(m) \ - { \ - _pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \ - _pico_free_parser( p ); \ - FreeObjVertexData( vertexData ); \ - PicoFreeModel( model ); \ - return NULL; \ - } - /* alllocate 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 ); - - /* try loading the materials; we don't handle the result */ -#if 0 - _obj_mtl_load( model ); -#endif - - /* parse obj line by line */ - while( 1 ) - { - /* get first token on line */ - if (_pico_parse_first( p ) == NULL) - break; - - /* skip empty lines */ - if (p->token == NULL || !strlen( p->token )) - continue; - - /* skip comment lines */ - if (p->token[0] == '#') - { - _pico_parse_skip_rest( p ); - continue; - } - /* vertex */ - if (!_pico_stricmp(p->token,"v")) - { - TObjVertexData *data; - picoVec3_t v; - - vertexData = SizeObjVertexData( vertexData,numVerts+1,&entries,&allocated ); - if (vertexData == NULL) - _obj_error_return("Realloc of vertex data failed (1)"); - - data = &vertexData[ numVerts++ ]; - - /* get and copy vertex */ - if (!_pico_parse_vec( p,v )) - _obj_error_return("Vertex parse error"); - - _pico_copy_vec( v,data->v ); - -#ifdef DEBUG_PM_OBJ_EX - printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); -#endif - } - /* uv coord */ - else if (!_pico_stricmp(p->token,"vt")) - { - TObjVertexData *data; - picoVec2_t coord; - - vertexData = SizeObjVertexData( vertexData,numUVs+1,&entries,&allocated ); - if (vertexData == NULL) - _obj_error_return("Realloc of vertex data failed (2)"); - - data = &vertexData[ numUVs++ ]; - - /* get and copy tex coord */ - if (!_pico_parse_vec2( p,coord )) - _obj_error_return("UV coord parse error"); - - _pico_copy_vec2( coord,data->vt ); - -#ifdef DEBUG_PM_OBJ_EX - printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]); -#endif - } - /* vertex normal */ - else if (!_pico_stricmp(p->token,"vn")) - { - TObjVertexData *data; - picoVec3_t n; - - vertexData = SizeObjVertexData( vertexData,numNormals+1,&entries,&allocated ); - if (vertexData == NULL) - _obj_error_return("Realloc of vertex data failed (3)"); - - data = &vertexData[ numNormals++ ]; - - /* get and copy vertex normal */ - if (!_pico_parse_vec( p,n )) - _obj_error_return("Vertex normal parse error"); - - _pico_copy_vec( n,data->vn ); - -#ifdef DEBUG_PM_OBJ_EX - printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]); -#endif - } - /* new group (for us this means a new surface) */ - else if (!_pico_stricmp(p->token,"g")) - { - picoSurface_t *newSurface; - char *groupName; - - /* get first group name (ignore 2nd,3rd,etc.) */ - groupName = _pico_parse( p,0 ); - if (groupName == NULL || !strlen(groupName)) - { - /* some obj exporters feel like they don't need to */ - /* supply a group name. so we gotta handle it here */ -#if 1 - strcpy( p->token,"default" ); - groupName = p->token; -#else - _obj_error_return("Invalid or missing group name"); -#endif - } - /* allocate a pico surface */ - newSurface = PicoNewSurface( model ); - if (newSurface == NULL) - _obj_error_return("Error allocating surface"); - - /* reset face index for surface */ - curFace = 0; - - /* set ptr to current surface */ - curSurface = newSurface; - - /* we use triangle meshes */ - PicoSetSurfaceType( newSurface,PICO_TRIANGLES ); - - /* set surface name */ - PicoSetSurfaceName( newSurface,groupName ); - -#ifdef DEBUG_PM_OBJ_EX - printf("Group: '%s'\n",groupName); -#endif - } - /* face (oh jesus, hopefully this will do the job right ;) */ - else if (!_pico_stricmp(p->token,"f")) - { - /* okay, this is a mess. some 3d apps seem to try being unique, */ - /* hello cinema4d & 3d exploration, feel good today?, and save */ - /* this crap in tons of different formats. gah, those screwed */ - /* coders. tho the wavefront obj standard defines exactly two */ - /* ways of storing face information. so, i really won't support */ - /* such stupid extravaganza here! */ - - picoVec3_t verts [ 4 ]; - picoVec3_t normals[ 4 ]; - picoVec2_t coords [ 4 ]; - - int iv [ 4 ], has_v; - int ivt[ 4 ], has_vt = 0; - int ivn[ 4 ], has_vn = 0; - int have_quad = 0; - int slashcount; - int doubleslash; - int i; - - /* group defs *must* come before faces */ - if (curSurface == NULL) - _obj_error_return("No group defined for faces"); - -#ifdef DEBUG_PM_OBJ_EX - printf("Face: "); -#endif - /* read vertex/uv/normal indices for the first three face */ - /* vertices (cause we only support triangles) into 'i*[]' */ - /* store the actual vertex/uv/normal data in three arrays */ - /* called 'verts','coords' and 'normals'. */ - for (i=0; i<4; i++) - { - char *str; - - /* get next vertex index string (different */ - /* formats are handled below) */ - str = _pico_parse( p,0 ); - if (str == NULL) - { - /* just break for quads */ - if (i == 3) break; - - /* error otherwise */ - _obj_error_return("Face parse error"); - } - /* if this is the fourth index string we're */ - /* parsing we assume that we have a quad */ - if (i == 3) - have_quad = 1; - - /* get slash count once */ - if (i == 0) - { - slashcount = _pico_strchcount( str,'/' ); - doubleslash = strstr(str,"//") != NULL; - } - /* handle format 'v//vn' */ - if (doubleslash && (slashcount == 2)) - { - has_v = has_vn = 1; - sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] ); - } - /* handle format 'v/vt/vn' */ - else if (!doubleslash && (slashcount == 2)) - { - has_v = has_vt = has_vn = 1; - sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] ); - } - /* handle format 'v/vt' (non-standard fuckage) */ - else if (!doubleslash && (slashcount == 1)) - { - has_v = has_vt = 1; - sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] ); - } - /* else assume face format 'v' */ - /* (must have been invented by some bored granny) */ - else { - /* get single vertex index */ - has_v = 1; - iv[ i ] = atoi( str ); - - /* either invalid face format or out of range */ - if (iv[ i ] == 0) - _obj_error_return("Invalid face format"); - } - /* fix useless back references */ - /* todo: check if this works as it is supposed to */ - - /* assign new indices */ - if (iv [ i ] < 0) iv [ i ] = (numVerts - iv [ i ]); - if (ivt[ i ] < 0) ivt[ i ] = (numUVs - ivt[ i ]); - if (ivn[ i ] < 0) ivn[ i ] = (numNormals - ivn[ i ]); - - /* validate indices */ - /* - commented out. index range checks will trigger - if (iv [ i ] < 1) iv [ i ] = 1; - if (ivt[ i ] < 1) ivt[ i ] = 1; - if (ivn[ i ] < 1) ivn[ i ] = 1; - */ - /* set vertex origin */ - if (has_v) - { - /* check vertex index range */ - if (iv[ i ] < 1 || iv[ i ] > numVerts) - _obj_error_return("Vertex index out of range"); - - /* get vertex data */ - verts[ i ][ 0 ] = vertexData[ iv[ i ] - 1 ].v[ 0 ]; - verts[ i ][ 1 ] = vertexData[ iv[ i ] - 1 ].v[ 1 ]; - verts[ i ][ 2 ] = vertexData[ iv[ i ] - 1 ].v[ 2 ]; - } - /* set vertex normal */ - if (has_vn) - { - /* check normal index range */ - if (ivn[ i ] < 1 || ivn[ i ] > numNormals) - _obj_error_return("Normal index out of range"); - - /* get normal data */ - normals[ i ][ 0 ] = vertexData[ ivn[ i ] - 1 ].vn[ 0 ]; - normals[ i ][ 1 ] = vertexData[ ivn[ i ] - 1 ].vn[ 1 ]; - normals[ i ][ 2 ] = vertexData[ ivn[ i ] - 1 ].vn[ 2 ]; - } - /* set texture coordinate */ - if (has_vt) - { - /* check uv index range */ - if (ivt[ i ] < 1 || ivt[ i ] > numUVs) - _obj_error_return("UV coord index out of range"); - - /* get uv coord data */ - coords[ i ][ 0 ] = vertexData[ ivt[ i ] - 1 ].vt[ 0 ]; - coords[ i ][ 1 ] = vertexData[ ivt[ i ] - 1 ].vt[ 1 ]; - coords[ i ][ 1 ] = -coords[ i ][ 1 ]; - } -#ifdef DEBUG_PM_OBJ_EX - printf("(%4d",iv[ i ]); - if (has_vt) printf(" %4d",ivt[ i ]); - if (has_vn) printf(" %4d",ivn[ i ]); - printf(") "); -#endif - } -#ifdef DEBUG_PM_OBJ_EX - printf("\n"); -#endif - /* now that we have extracted all the indices and have */ - /* read the actual data we need to assign all the crap */ - /* to our current pico surface */ - if (has_v) - { - int max = 3; - if (have_quad) max = 4; - - /* assign all surface information */ - for (i=0; i<max; i++) - { - /*if( has_v )*/ PicoSetSurfaceXYZ ( curSurface, (curVertex + i), verts [ i ] ); - /*if( has_vt )*/ PicoSetSurfaceST ( curSurface,0,(curVertex + i), coords [ i ] ); - /*if( has_vn )*/ PicoSetSurfaceNormal( curSurface, (curVertex + i), normals[ i ] ); - } - /* add our triangle (A B C) */ - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) ); - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 1 ) ); - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 2 ) ); - curFace++; - - /* if we don't have a simple triangle, but a quad... */ - if (have_quad) - { - /* we have to add another triangle (2nd half of quad which is A C D) */ - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) ); - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 2 ) ); - PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 3 ) ); - curFace++; - } - /* increase vertex count */ - curVertex += max; - } - } - /* skip unparsed rest of line and continue */ - _pico_parse_skip_rest( p ); - } - /* free memory used by temporary vertexdata */ - FreeObjVertexData( vertexData ); - - /* return allocated pico model */ - return model; -// return NULL; -} - -/* pico file format module definition */ -const picoModule_t picoModuleOBJ = -{ - "0.6-b", /* module version string */ - "Wavefront ASCII", /* module display name */ - "seaw0lf", /* author's name */ - "2002 seaw0lf", /* module copyright */ - { - "obj",NULL,NULL,NULL /* default extensions to use */ - }, - _obj_canload, /* validation routine */ - _obj_load, /* load routine */ - NULL, /* save validation routine */ - NULL /* save routine */ -}; +/* ----------------------------------------------------------------------------- + +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_OBJ_C + +/* dependencies */ +#include "picointernal.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4100 ) /* unref param */ +#endif + +/* todo: + * - '_obj_load' code crashes in a weird way after + * '_obj_mtl_load' for a few .mtl files + * - process 'mtllib' rather than using <model>.mtl + * - handle 'usemtl' statements + */ +/* uncomment when debugging this module */ +/* #define DEBUG_PM_OBJ */ +/* #define DEBUG_PM_OBJ_EX */ + +/* this holds temporary vertex data read by parser */ +typedef struct SObjVertexData +{ + picoVec3_t v; /* geometric vertices */ + picoVec2_t vt; /* texture vertices */ + picoVec3_t vn; /* vertex normals (optional) */ +} +TObjVertexData; + +/* _obj_canload: + * validates a wavefront obj model file. + */ +static int _obj_canload( PM_PARAMS_CANLOAD ) +{ + picoParser_t *p; + + /* check data length */ + if (bufSize < 30) + return PICO_PMV_ERROR_SIZE; + + /* first check file extension. we have to do this for objs */ + /* cause there is no good way to identify the contents */ + if (_pico_stristr(fileName,".obj") != NULL || + _pico_stristr(fileName,".wf" ) != NULL) + { + return PICO_PMV_OK; + } + /* if the extension check failed we parse through the first */ + /* few lines in file and look for common keywords often */ + /* appearing at the beginning of wavefront objects */ + + /* alllocate a new pico parser */ + p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); + if (p == NULL) + return PICO_PMV_ERROR_MEMORY; + + /* parse obj head line by line for type check */ + while( 1 ) + { + /* get first token on line */ + if (_pico_parse_first( p ) == NULL) + break; + + /* we only parse the first few lines, say 80 */ + if (p->curLine > 80) + break; + + /* skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* material library keywords are teh good */ + if (!_pico_stricmp(p->token,"usemtl") || + !_pico_stricmp(p->token,"mtllib") || + !_pico_stricmp(p->token,"g") || + !_pico_stricmp(p->token,"v")) /* v,g bit fishy, but uh... */ + { + /* free the pico parser thing */ + _pico_free_parser( p ); + + /* seems to be a valid wavefront obj */ + return PICO_PMV_OK; + } + /* skip rest of line */ + _pico_parse_skip_rest( p ); + } + /* free the pico parser thing */ + _pico_free_parser( p ); + + /* doesn't really look like an obj to us */ + return PICO_PMV_ERROR; +} + +/* SizeObjVertexData: + * This pretty piece of 'alloc ahead' code dynamically + * allocates - and reallocates as soon as required - + * my vertex data array in even steps. + */ +#define SIZE_OBJ_STEP 4096 + +static TObjVertexData *SizeObjVertexData( + TObjVertexData *vertexData, int reqEntries, + int *entries, int *allocated) +{ + int newAllocated; + + /* sanity checks */ + if (reqEntries < 1) + return NULL; + if (entries == NULL || allocated == NULL) + return NULL; /* must have */ + + /* no need to grow yet */ + if (vertexData && (reqEntries < *allocated)) + { + *entries = reqEntries; + return vertexData; + } + /* given vertex data ptr not allocated yet */ + if (vertexData == NULL) + { + /* how many entries to allocate */ + newAllocated = (reqEntries > SIZE_OBJ_STEP) ? + reqEntries : SIZE_OBJ_STEP; + + /* throw out an extended debug message */ +#ifdef DEBUG_PM_OBJ_EX + printf("SizeObjVertexData: allocate (%d entries)\n", + newAllocated); +#endif + /* first time allocation */ + vertexData = (TObjVertexData *) + _pico_alloc( sizeof(TObjVertexData) * newAllocated ); + + /* allocation failed */ + if (vertexData == NULL) + return NULL; + + /* allocation succeeded */ + *allocated = newAllocated; + *entries = reqEntries; + return vertexData; + } + /* given vertex data ptr needs to be resized */ + if (reqEntries == *allocated) + { + newAllocated = (*allocated + SIZE_OBJ_STEP); + + /* throw out an extended debug message */ +#ifdef DEBUG_PM_OBJ_EX + printf("SizeObjVertexData: reallocate (%d entries)\n", + newAllocated); +#endif + /* try to reallocate */ + vertexData = (TObjVertexData *) + _pico_realloc( (void *)&vertexData, + sizeof(TObjVertexData) * (*allocated), + sizeof(TObjVertexData) * (newAllocated)); + + /* reallocation failed */ + if (vertexData == NULL) + return NULL; + + /* reallocation succeeded */ + *allocated = newAllocated; + *entries = reqEntries; + return vertexData; + } + /* we're b0rked when we reach this */ + return NULL; +} + +static void FreeObjVertexData( TObjVertexData *vertexData ) +{ + if (vertexData != NULL) + { + free( (TObjVertexData *)vertexData ); + } +} + +static int _obj_mtl_load( picoModel_t *model ) +{ + picoShader_t *curShader = NULL; + picoParser_t *p; + picoByte_t *mtlBuffer; + int mtlBufSize; + char *fileName; + + /* sanity checks */ + if( model == NULL || model->fileName == NULL ) + return 0; + + /* skip if we have a zero length model file name */ + if (!strlen( model->fileName )) + return 0; + + /* helper */ + #define _obj_mtl_error_return \ + { \ + _pico_free_parser( p ); \ + _pico_free_file( mtlBuffer ); \ + _pico_free( fileName ); \ + return 0; \ + } + /* alloc copy of model file name */ + fileName = _pico_clone_alloc( model->fileName,-1 ); + if (fileName == NULL) + return 0; + + /* change extension of model file to .mtl */ + _pico_setfext( fileName, "mtl" ); + + /* load .mtl file contents */ + _pico_load_file( fileName,&mtlBuffer,&mtlBufSize ); + + /* check result */ + if (mtlBufSize == 0) return 1; /* file is empty: no error */ + if (mtlBufSize < 0) return 0; /* load failed: error */ + + /* create a new pico parser */ + p = _pico_new_parser( mtlBuffer, mtlBufSize ); + if (p == NULL) + _obj_mtl_error_return; + + /* doo teh .mtl parse */ + while( 1 ) + { + /* get next token in material file */ + if (_pico_parse( p,1 ) == NULL) + break; +#if 0 + + /* skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* skip comment lines */ + if (p->token[0] == '#') + { + _pico_parse_skip_rest( p ); + continue; + } + /* new material */ + if (!_pico_stricmp(p->token,"newmtl")) + { + picoShader_t *shader; + char *name; + + /* get material name */ + name = _pico_parse( p,0 ); + + /* validate material name */ + if (name == NULL || !strlen(name)) + { + _pico_printf( PICO_ERROR,"Missing material name in MTL, line %d.",p->curLine); + _obj_mtl_error_return; + } + /* create a new pico shader */ + shader = PicoNewShader( model ); + if (shader == NULL) + _obj_mtl_error_return; + + /* set shader name */ + PicoSetShaderName( shader,name ); + + /* assign pointer to current shader */ + curShader = shader; + } + /* diffuse map name */ + else if (!_pico_stricmp(p->token,"map_kd")) + { + char *mapName; + + /* pointer to current shader must be valid */ + if (curShader == NULL) + _obj_mtl_error_return; + + /* get material's diffuse map name */ + mapName = _pico_parse( p,0 ); + + /* validate map name */ + if (mapName == NULL || !strlen(mapName)) + { + _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine); + _obj_mtl_error_return; + } + /* set shader map name */ + PicoSetShaderMapName( shader,mapName ); + } + /* dissolve factor (pseudo transparency 0..1) */ + /* where 0 means 100% transparent and 1 means opaque */ + else if (!_pico_stricmp(p->token,"d")) + { + picoByte_t *diffuse; + float value; + + + /* get dissolve factor */ + if (!_pico_parse_float( p,&value )) + _obj_mtl_error_return; + + /* set shader transparency */ + PicoSetShaderTransparency( curShader,value ); + + /* get shader's diffuse color */ + diffuse = PicoGetShaderDiffuseColor( curShader ); + + /* set diffuse alpha to transparency */ + diffuse[ 3 ] = (picoByte_t)( value * 255.0 ); + + /* set shader's new diffuse color */ + PicoSetShaderDiffuseColor( curShader,diffuse ); + } + /* shininess (phong specular component) */ + else if (!_pico_stricmp(p->token,"ns")) + { + /* remark: + * - well, this is some major obj spec fuckup once again. some + * apps store this in 0..1 range, others use 0..100 range, + * even others use 0..2048 range, and again others use the + * range 0..128, some even use 0..1000, 0..200, 400..700, + * honestly, what's up with the 3d app coders? happens when + * you smoke too much weed i guess. -sea + */ + float value; + + /* pointer to current shader must be valid */ + if (curShader == NULL) + _obj_mtl_error_return; + + /* get totally screwed up shininess (a random value in fact ;) */ + if (!_pico_parse_float( p,&value )) + _obj_mtl_error_return; + + /* okay, there is no way to set this correctly, so we simply */ + /* try to guess a few ranges (most common ones i have seen) */ + + /* assume 0..2048 range */ + if (value > 1000) + value = 128.0 * (value / 2048.0); + /* assume 0..1000 range */ + else if (value > 200) + value = 128.0 * (value / 1000.0); + /* assume 0..200 range */ + else if (value > 100) + value = 128.0 * (value / 200.0); + /* assume 0..100 range */ + else if (value > 1) + value = 128.0 * (value / 100.0); + /* assume 0..1 range */ + else { + value *= 128.0; + } + /* negative shininess is bad (yes, i have seen it...) */ + if (value < 0.0) value = 0.0; + + /* set the pico shininess value in range 0..127 */ + /* geez, .obj is such a mess... */ + PicoSetShaderShininess( curShader,value ); + } + /* kol0r ambient (wut teh fuk does "ka" stand for?) */ + else if (!_pico_stricmp(p->token,"ka")) + { + picoColor_t color; + picoVec3_t v; + + /* pointer to current shader must be valid */ + if (curShader == NULL) + _obj_mtl_error_return; + + /* get color vector */ + if (!_pico_parse_vec( p,v )) + _obj_mtl_error_return; + + /* scale to byte range */ + color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); + color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); + color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); + color[ 3 ] = (picoByte_t)( 255 ); + + /* set ambient color */ + PicoSetShaderAmbientColor( curShader,color ); + } + /* kol0r diffuse */ + else if (!_pico_stricmp(p->token,"kd")) + { + picoColor_t color; + picoVec3_t v; + + /* pointer to current shader must be valid */ + if (curShader == NULL) + _obj_mtl_error_return; + + /* get color vector */ + if (!_pico_parse_vec( p,v )) + _obj_mtl_error_return; + + /* scale to byte range */ + color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); + color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); + color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); + color[ 3 ] = (picoByte_t)( 255 ); + + /* set diffuse color */ + PicoSetShaderDiffuseColor( curShader,color ); + } + /* kol0r specular */ + else if (!_pico_stricmp(p->token,"ks")) + { + picoColor_t color; + picoVec3_t v; + + /* pointer to current shader must be valid */ + if (curShader == NULL) + _obj_mtl_error_return; + + /* get color vector */ + if (!_pico_parse_vec( p,v )) + _obj_mtl_error_return; + + /* scale to byte range */ + color[ 0 ] = (picoByte_t)( v[ 0 ] * 255 ); + color[ 1 ] = (picoByte_t)( v[ 1 ] * 255 ); + color[ 2 ] = (picoByte_t)( v[ 2 ] * 255 ); + color[ 3 ] = (picoByte_t)( 255 ); + + /* set specular color */ + PicoSetShaderSpecularColor( curShader,color ); + } +#endif + /* skip rest of line */ + _pico_parse_skip_rest( p ); + } + + /* free parser, file buffer, and file name */ + _pico_free_parser( p ); + _pico_free_file( mtlBuffer ); + _pico_free( fileName ); + + /* return with success */ + return 1; +} + +/* _obj_load: + * loads a wavefront obj model file. +*/ +static picoModel_t *_obj_load( PM_PARAMS_LOAD ) +{ + TObjVertexData *vertexData = NULL; + picoModel_t *model; + picoSurface_t *curSurface = NULL; + picoParser_t *p; + int allocated; + int entries; + int numVerts = 0; + int numNormals = 0; + int numUVs = 0; + int curVertex = 0; + int curFace = 0; + + /* helper */ + #define _obj_error_return(m) \ + { \ + _pico_printf( PICO_ERROR,"%s in OBJ, line %d.",m,p->curLine); \ + _pico_free_parser( p ); \ + FreeObjVertexData( vertexData ); \ + PicoFreeModel( model ); \ + return NULL; \ + } + /* alllocate 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 ); + + /* try loading the materials; we don't handle the result */ +#if 0 + _obj_mtl_load( model ); +#endif + + /* parse obj line by line */ + while( 1 ) + { + /* get first token on line */ + if (_pico_parse_first( p ) == NULL) + break; + + /* skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* skip comment lines */ + if (p->token[0] == '#') + { + _pico_parse_skip_rest( p ); + continue; + } + /* vertex */ + if (!_pico_stricmp(p->token,"v")) + { + TObjVertexData *data; + picoVec3_t v; + + vertexData = SizeObjVertexData( vertexData,numVerts+1,&entries,&allocated ); + if (vertexData == NULL) + _obj_error_return("Realloc of vertex data failed (1)"); + + data = &vertexData[ numVerts++ ]; + + /* get and copy vertex */ + if (!_pico_parse_vec( p,v )) + _obj_error_return("Vertex parse error"); + + _pico_copy_vec( v,data->v ); + +#ifdef DEBUG_PM_OBJ_EX + printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); +#endif + } + /* uv coord */ + else if (!_pico_stricmp(p->token,"vt")) + { + TObjVertexData *data; + picoVec2_t coord; + + vertexData = SizeObjVertexData( vertexData,numUVs+1,&entries,&allocated ); + if (vertexData == NULL) + _obj_error_return("Realloc of vertex data failed (2)"); + + data = &vertexData[ numUVs++ ]; + + /* get and copy tex coord */ + if (!_pico_parse_vec2( p,coord )) + _obj_error_return("UV coord parse error"); + + _pico_copy_vec2( coord,data->vt ); + +#ifdef DEBUG_PM_OBJ_EX + printf("TexCoord: u: %f v: %f\n",coord[0],coord[1]); +#endif + } + /* vertex normal */ + else if (!_pico_stricmp(p->token,"vn")) + { + TObjVertexData *data; + picoVec3_t n; + + vertexData = SizeObjVertexData( vertexData,numNormals+1,&entries,&allocated ); + if (vertexData == NULL) + _obj_error_return("Realloc of vertex data failed (3)"); + + data = &vertexData[ numNormals++ ]; + + /* get and copy vertex normal */ + if (!_pico_parse_vec( p,n )) + _obj_error_return("Vertex normal parse error"); + + _pico_copy_vec( n,data->vn ); + +#ifdef DEBUG_PM_OBJ_EX + printf("Normal: x: %f y: %f z: %f\n",n[0],n[1],n[2]); +#endif + } + /* new group (for us this means a new surface) */ + else if (!_pico_stricmp(p->token,"g")) + { + picoSurface_t *newSurface; + char *groupName; + + /* get first group name (ignore 2nd,3rd,etc.) */ + groupName = _pico_parse( p,0 ); + if (groupName == NULL || !strlen(groupName)) + { + /* some obj exporters feel like they don't need to */ + /* supply a group name. so we gotta handle it here */ +#if 1 + strcpy( p->token,"default" ); + groupName = p->token; +#else + _obj_error_return("Invalid or missing group name"); +#endif + } + /* allocate a pico surface */ + newSurface = PicoNewSurface( model ); + if (newSurface == NULL) + _obj_error_return("Error allocating surface"); + + /* reset face index for surface */ + curFace = 0; + + /* set ptr to current surface */ + curSurface = newSurface; + + /* we use triangle meshes */ + PicoSetSurfaceType( newSurface,PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( newSurface,groupName ); + +#ifdef DEBUG_PM_OBJ_EX + printf("Group: '%s'\n",groupName); +#endif + } + /* face (oh jesus, hopefully this will do the job right ;) */ + else if (!_pico_stricmp(p->token,"f")) + { + /* okay, this is a mess. some 3d apps seem to try being unique, */ + /* hello cinema4d & 3d exploration, feel good today?, and save */ + /* this crap in tons of different formats. gah, those screwed */ + /* coders. tho the wavefront obj standard defines exactly two */ + /* ways of storing face information. so, i really won't support */ + /* such stupid extravaganza here! */ + + picoVec3_t verts [ 4 ]; + picoVec3_t normals[ 4 ]; + picoVec2_t coords [ 4 ]; + + int iv [ 4 ], has_v; + int ivt[ 4 ], has_vt = 0; + int ivn[ 4 ], has_vn = 0; + int have_quad = 0; + int slashcount; + int doubleslash; + int i; + + /* group defs *must* come before faces */ + if (curSurface == NULL) + _obj_error_return("No group defined for faces"); + +#ifdef DEBUG_PM_OBJ_EX + printf("Face: "); +#endif + /* read vertex/uv/normal indices for the first three face */ + /* vertices (cause we only support triangles) into 'i*[]' */ + /* store the actual vertex/uv/normal data in three arrays */ + /* called 'verts','coords' and 'normals'. */ + for (i=0; i<4; i++) + { + char *str; + + /* get next vertex index string (different */ + /* formats are handled below) */ + str = _pico_parse( p,0 ); + if (str == NULL) + { + /* just break for quads */ + if (i == 3) break; + + /* error otherwise */ + _obj_error_return("Face parse error"); + } + /* if this is the fourth index string we're */ + /* parsing we assume that we have a quad */ + if (i == 3) + have_quad = 1; + + /* get slash count once */ + if (i == 0) + { + slashcount = _pico_strchcount( str,'/' ); + doubleslash = strstr(str,"//") != NULL; + } + /* handle format 'v//vn' */ + if (doubleslash && (slashcount == 2)) + { + has_v = has_vn = 1; + sscanf( str,"%d//%d",&iv[ i ],&ivn[ i ] ); + } + /* handle format 'v/vt/vn' */ + else if (!doubleslash && (slashcount == 2)) + { + has_v = has_vt = has_vn = 1; + sscanf( str,"%d/%d/%d",&iv[ i ],&ivt[ i ],&ivn[ i ] ); + } + /* handle format 'v/vt' (non-standard fuckage) */ + else if (!doubleslash && (slashcount == 1)) + { + has_v = has_vt = 1; + sscanf( str,"%d/%d",&iv[ i ],&ivt[ i ] ); + } + /* else assume face format 'v' */ + /* (must have been invented by some bored granny) */ + else { + /* get single vertex index */ + has_v = 1; + iv[ i ] = atoi( str ); + + /* either invalid face format or out of range */ + if (iv[ i ] == 0) + _obj_error_return("Invalid face format"); + } + /* fix useless back references */ + /* todo: check if this works as it is supposed to */ + + /* assign new indices */ + if (iv [ i ] < 0) iv [ i ] = (numVerts - iv [ i ]); + if (ivt[ i ] < 0) ivt[ i ] = (numUVs - ivt[ i ]); + if (ivn[ i ] < 0) ivn[ i ] = (numNormals - ivn[ i ]); + + /* validate indices */ + /* - commented out. index range checks will trigger + if (iv [ i ] < 1) iv [ i ] = 1; + if (ivt[ i ] < 1) ivt[ i ] = 1; + if (ivn[ i ] < 1) ivn[ i ] = 1; + */ + /* set vertex origin */ + if (has_v) + { + /* check vertex index range */ + if (iv[ i ] < 1 || iv[ i ] > numVerts) + _obj_error_return("Vertex index out of range"); + + /* get vertex data */ + verts[ i ][ 0 ] = vertexData[ iv[ i ] - 1 ].v[ 0 ]; + verts[ i ][ 1 ] = vertexData[ iv[ i ] - 1 ].v[ 1 ]; + verts[ i ][ 2 ] = vertexData[ iv[ i ] - 1 ].v[ 2 ]; + } + /* set vertex normal */ + if (has_vn) + { + /* check normal index range */ + if (ivn[ i ] < 1 || ivn[ i ] > numNormals) + _obj_error_return("Normal index out of range"); + + /* get normal data */ + normals[ i ][ 0 ] = vertexData[ ivn[ i ] - 1 ].vn[ 0 ]; + normals[ i ][ 1 ] = vertexData[ ivn[ i ] - 1 ].vn[ 1 ]; + normals[ i ][ 2 ] = vertexData[ ivn[ i ] - 1 ].vn[ 2 ]; + } + /* set texture coordinate */ + if (has_vt) + { + /* check uv index range */ + if (ivt[ i ] < 1 || ivt[ i ] > numUVs) + _obj_error_return("UV coord index out of range"); + + /* get uv coord data */ + coords[ i ][ 0 ] = vertexData[ ivt[ i ] - 1 ].vt[ 0 ]; + coords[ i ][ 1 ] = vertexData[ ivt[ i ] - 1 ].vt[ 1 ]; + coords[ i ][ 1 ] = -coords[ i ][ 1 ]; + } +#ifdef DEBUG_PM_OBJ_EX + printf("(%4d",iv[ i ]); + if (has_vt) printf(" %4d",ivt[ i ]); + if (has_vn) printf(" %4d",ivn[ i ]); + printf(") "); +#endif + } +#ifdef DEBUG_PM_OBJ_EX + printf("\n"); +#endif + /* now that we have extracted all the indices and have */ + /* read the actual data we need to assign all the crap */ + /* to our current pico surface */ + if (has_v) + { + int max = 3; + if (have_quad) max = 4; + + /* assign all surface information */ + for (i=0; i<max; i++) + { + /*if( has_v )*/ PicoSetSurfaceXYZ ( curSurface, (curVertex + i), verts [ i ] ); + /*if( has_vt )*/ PicoSetSurfaceST ( curSurface,0,(curVertex + i), coords [ i ] ); + /*if( has_vn )*/ PicoSetSurfaceNormal( curSurface, (curVertex + i), normals[ i ] ); + } + /* add our triangle (A B C) */ + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) ); + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 1 ) ); + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 2 ) ); + curFace++; + + /* if we don't have a simple triangle, but a quad... */ + if (have_quad) + { + /* we have to add another triangle (2nd half of quad which is A C D) */ + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 2),(picoIndex_t)( curVertex + 0 ) ); + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 1),(picoIndex_t)( curVertex + 2 ) ); + PicoSetSurfaceIndex( curSurface,(curFace * 3 + 0),(picoIndex_t)( curVertex + 3 ) ); + curFace++; + } + /* increase vertex count */ + curVertex += max; + } + } + /* skip unparsed rest of line and continue */ + _pico_parse_skip_rest( p ); + } + /* free memory used by temporary vertexdata */ + FreeObjVertexData( vertexData ); + + /* return allocated pico model */ + return model; +// return NULL; +} + +/* pico file format module definition */ +const picoModule_t picoModuleOBJ = +{ + "0.6-b", /* module version string */ + "Wavefront ASCII", /* module display name */ + "seaw0lf", /* author's name */ + "2002 seaw0lf", /* module copyright */ + { + "obj",NULL,NULL,NULL /* default extensions to use */ + }, + _obj_canload, /* validation routine */ + _obj_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/splines/math_angles.h b/libs/splines/math_angles.h index 17e3fbfa..b095fae3 100644 --- a/libs/splines/math_angles.h +++ b/libs/splines/math_angles.h @@ -1,195 +1,195 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __MATH_ANGLES_H__ -#define __MATH_ANGLES_H__ - -#include <stdlib.h> -#include <assert.h> - -#include "math_vector.h" - -class mat3_t; -class quat_t; -class idVec3; -typedef idVec3 &vec3_p; - -class angles_t { -public: - float pitch; - float yaw; - float roll; - - angles_t(); - angles_t( float pitch, float yaw, float roll ); - angles_t( const idVec3 &vec ); - - friend void toAngles( idVec3 &src, angles_t &dst ); - friend void toAngles( quat_t &src, angles_t &dst ); - friend void toAngles( mat3_t &src, angles_t &dst ); - - operator vec3_p(); - - float operator[]( int index ) const; - float& operator[]( int index ); - - void set( float pitch, float yaw, float roll ); - - void operator=( angles_t const &a ); - void operator=( idVec3 const &a ); - - friend angles_t operator+( const angles_t &a, const angles_t &b ); - angles_t &operator+=( angles_t const &a ); - angles_t &operator+=( idVec3 const &a ); - - friend angles_t operator-( angles_t &a, angles_t &b ); - angles_t &operator-=( angles_t &a ); - - friend angles_t operator*( const angles_t &a, float b ); - friend angles_t operator*( float a, const angles_t &b ); - angles_t &operator*=( float a ); - - friend int operator==( angles_t &a, angles_t &b ); - - friend int operator!=( angles_t &a, angles_t &b ); - - void toVectors( idVec3 *forward, idVec3 *right = NULL, idVec3 *up = NULL ); - idVec3 toForward( void ); - - angles_t &Zero( void ); - - angles_t &Normalize360( void ); - angles_t &Normalize180( void ); -}; - -extern angles_t ang_zero; - -inline angles_t::angles_t() {} - -inline angles_t::angles_t( float pitch, float yaw, float roll ) { - this->pitch = pitch; - this->yaw = yaw; - this->roll = roll; -} - -inline angles_t::angles_t( const idVec3 &vec ) { - this->pitch = vec.x; - this->yaw = vec.y; - this->roll = vec.z; -} - -inline float angles_t::operator[]( int index ) const { - assert( ( index >= 0 ) && ( index < 3 ) ); - return ( &pitch )[ index ]; -} - -inline float& angles_t::operator[]( int index ) { - assert( ( index >= 0 ) && ( index < 3 ) ); - return ( &pitch )[ index ]; -} - -inline angles_t::operator vec3_p( void ) { - return *( idVec3 * )&pitch; -} - -inline void angles_t::set( float pitch, float yaw, float roll ) { - this->pitch = pitch; - this->yaw = yaw; - this->roll = roll; -} - -inline void angles_t::operator=( angles_t const &a ) { - pitch = a.pitch; - yaw = a.yaw; - roll = a.roll; -} - -inline void angles_t::operator=( idVec3 const &a ) { - pitch = a[ 0 ]; - yaw = a[ 1 ]; - roll = a[ 2 ]; -} - -inline angles_t operator+( const angles_t &a, const angles_t &b ) { - return angles_t( a.pitch + b.pitch, a.yaw + b.yaw, a.roll + b.roll ); -} - -inline angles_t& angles_t::operator+=( angles_t const &a ) { - pitch += a.pitch; - yaw += a.yaw; - roll += a.roll; - - return *this; -} - -inline angles_t& angles_t::operator+=( idVec3 const &a ) { - pitch += a.x; - yaw += a.y; - roll += a.z; - - return *this; -} - -inline angles_t operator-( angles_t &a, angles_t &b ) { - return angles_t( a.pitch - b.pitch, a.yaw - b.yaw, a.roll - b.roll ); -} - -inline angles_t& angles_t::operator-=( angles_t &a ) { - pitch -= a.pitch; - yaw -= a.yaw; - roll -= a.roll; - - return *this; -} - -inline angles_t operator*( const angles_t &a, float b ) { - return angles_t( a.pitch * b, a.yaw * b, a.roll * b ); -} - -inline angles_t operator*( float a, const angles_t &b ) { - return angles_t( a * b.pitch, a * b.yaw, a * b.roll ); -} - -inline angles_t& angles_t::operator*=( float a ) { - pitch *= a; - yaw *= a; - roll *= a; - - return *this; -} - -inline int operator==( angles_t &a, angles_t &b ) { - return ( ( a.pitch == b.pitch ) && ( a.yaw == b.yaw ) && ( a.roll == b.roll ) ); -} - -inline int operator!=( angles_t &a, angles_t &b ) { - return ( ( a.pitch != b.pitch ) || ( a.yaw != b.yaw ) || ( a.roll != b.roll ) ); -} - -inline angles_t& angles_t::Zero( void ) { - pitch = 0.0f; - yaw = 0.0f; - roll = 0.0f; - - return *this; -} - -#endif /* !__MATH_ANGLES_H__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __MATH_ANGLES_H__ +#define __MATH_ANGLES_H__ + +#include <stdlib.h> +#include <assert.h> + +#include "math_vector.h" + +class mat3_t; +class quat_t; +class idVec3; +typedef idVec3 &vec3_p; + +class angles_t { +public: + float pitch; + float yaw; + float roll; + + angles_t(); + angles_t( float pitch, float yaw, float roll ); + angles_t( const idVec3 &vec ); + + friend void toAngles( idVec3 &src, angles_t &dst ); + friend void toAngles( quat_t &src, angles_t &dst ); + friend void toAngles( mat3_t &src, angles_t &dst ); + + operator vec3_p(); + + float operator[]( int index ) const; + float& operator[]( int index ); + + void set( float pitch, float yaw, float roll ); + + void operator=( angles_t const &a ); + void operator=( idVec3 const &a ); + + friend angles_t operator+( const angles_t &a, const angles_t &b ); + angles_t &operator+=( angles_t const &a ); + angles_t &operator+=( idVec3 const &a ); + + friend angles_t operator-( angles_t &a, angles_t &b ); + angles_t &operator-=( angles_t &a ); + + friend angles_t operator*( const angles_t &a, float b ); + friend angles_t operator*( float a, const angles_t &b ); + angles_t &operator*=( float a ); + + friend int operator==( angles_t &a, angles_t &b ); + + friend int operator!=( angles_t &a, angles_t &b ); + + void toVectors( idVec3 *forward, idVec3 *right = NULL, idVec3 *up = NULL ); + idVec3 toForward( void ); + + angles_t &Zero( void ); + + angles_t &Normalize360( void ); + angles_t &Normalize180( void ); +}; + +extern angles_t ang_zero; + +inline angles_t::angles_t() {} + +inline angles_t::angles_t( float pitch, float yaw, float roll ) { + this->pitch = pitch; + this->yaw = yaw; + this->roll = roll; +} + +inline angles_t::angles_t( const idVec3 &vec ) { + this->pitch = vec.x; + this->yaw = vec.y; + this->roll = vec.z; +} + +inline float angles_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &pitch )[ index ]; +} + +inline float& angles_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &pitch )[ index ]; +} + +inline angles_t::operator vec3_p( void ) { + return *( idVec3 * )&pitch; +} + +inline void angles_t::set( float pitch, float yaw, float roll ) { + this->pitch = pitch; + this->yaw = yaw; + this->roll = roll; +} + +inline void angles_t::operator=( angles_t const &a ) { + pitch = a.pitch; + yaw = a.yaw; + roll = a.roll; +} + +inline void angles_t::operator=( idVec3 const &a ) { + pitch = a[ 0 ]; + yaw = a[ 1 ]; + roll = a[ 2 ]; +} + +inline angles_t operator+( const angles_t &a, const angles_t &b ) { + return angles_t( a.pitch + b.pitch, a.yaw + b.yaw, a.roll + b.roll ); +} + +inline angles_t& angles_t::operator+=( angles_t const &a ) { + pitch += a.pitch; + yaw += a.yaw; + roll += a.roll; + + return *this; +} + +inline angles_t& angles_t::operator+=( idVec3 const &a ) { + pitch += a.x; + yaw += a.y; + roll += a.z; + + return *this; +} + +inline angles_t operator-( angles_t &a, angles_t &b ) { + return angles_t( a.pitch - b.pitch, a.yaw - b.yaw, a.roll - b.roll ); +} + +inline angles_t& angles_t::operator-=( angles_t &a ) { + pitch -= a.pitch; + yaw -= a.yaw; + roll -= a.roll; + + return *this; +} + +inline angles_t operator*( const angles_t &a, float b ) { + return angles_t( a.pitch * b, a.yaw * b, a.roll * b ); +} + +inline angles_t operator*( float a, const angles_t &b ) { + return angles_t( a * b.pitch, a * b.yaw, a * b.roll ); +} + +inline angles_t& angles_t::operator*=( float a ) { + pitch *= a; + yaw *= a; + roll *= a; + + return *this; +} + +inline int operator==( angles_t &a, angles_t &b ) { + return ( ( a.pitch == b.pitch ) && ( a.yaw == b.yaw ) && ( a.roll == b.roll ) ); +} + +inline int operator!=( angles_t &a, angles_t &b ) { + return ( ( a.pitch != b.pitch ) || ( a.yaw != b.yaw ) || ( a.roll != b.roll ) ); +} + +inline angles_t& angles_t::Zero( void ) { + pitch = 0.0f; + yaw = 0.0f; + roll = 0.0f; + + return *this; +} + +#endif /* !__MATH_ANGLES_H__ */ diff --git a/libs/splines/math_matrix.h b/libs/splines/math_matrix.h index f2cfae0d..a039945c 100644 --- a/libs/splines/math_matrix.h +++ b/libs/splines/math_matrix.h @@ -1,223 +1,223 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __MATH_MATRIX_H__ -#define __MATH_MATRIX_H__ - -#include <string.h> -#include "math_vector.h" - -#ifndef ID_INLINE -#ifdef _WIN32 -#define ID_INLINE __inline -#else -#define ID_INLINE inline -#endif -#endif - -class quat_t; -class angles_t; - -class mat3_t { -public: - idVec3 mat[ 3 ]; - - mat3_t(); - mat3_t( float src[ 3 ][ 3 ] ); - mat3_t( idVec3 const &x, idVec3 const &y, idVec3 const &z ); - mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ); - - friend void toMatrix( quat_t const &src, mat3_t &dst ); - friend void toMatrix( angles_t const &src, mat3_t &dst ); - friend void toMatrix( idVec3 const &src, mat3_t &dst ); - - idVec3 operator[]( int index ) const; - idVec3 &operator[]( int index ); - - idVec3 operator*( const idVec3 &vec ) const; - mat3_t operator*( const mat3_t &a ) const; - mat3_t operator*( float a ) const; - mat3_t operator+( mat3_t const &a ) const; - mat3_t operator-( mat3_t const &a ) const; - - friend idVec3 operator*( const idVec3 &vec, const mat3_t &mat ); - friend mat3_t operator*( float a, mat3_t const &b ); - - mat3_t &operator*=( float a ); - mat3_t &operator+=( mat3_t const &a ); - mat3_t &operator-=( mat3_t const &a ); - - void Clear( void ); - - void ProjectVector( const idVec3 &src, idVec3 &dst ) const; - void UnprojectVector( const idVec3 &src, idVec3 &dst ) const; - - void OrthoNormalize( void ); - void Transpose( mat3_t &matrix ); - void Transpose( void ); - mat3_t Inverse( void ) const; - void Identity( void ); - - friend void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ); - friend mat3_t SkewSymmetric( idVec3 const &src ); -}; - -ID_INLINE mat3_t::mat3_t() { -} - -ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { - memcpy( mat, src, sizeof( src ) ); -} - -ID_INLINE mat3_t::mat3_t( idVec3 const &x, idVec3 const &y, idVec3 const &z ) { - mat[ 0 ].x = x.x; mat[ 0 ].y = x.y; mat[ 0 ].z = x.z; - mat[ 1 ].x = y.x; mat[ 1 ].y = y.y; mat[ 1 ].z = y.z; - mat[ 2 ].x = z.x; mat[ 2 ].y = z.y; mat[ 2 ].z = z.z; -} - -ID_INLINE mat3_t::mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ) { - mat[ 0 ].x = xx; mat[ 0 ].y = xy; mat[ 0 ].z = xz; - mat[ 1 ].x = yx; mat[ 1 ].y = yy; mat[ 1 ].z = yz; - mat[ 2 ].x = zx; mat[ 2 ].y = zy; mat[ 2 ].z = zz; -} - -ID_INLINE idVec3 mat3_t::operator[]( int index ) const { - assert( ( index >= 0 ) && ( index < 3 ) ); - return mat[ index ]; -} - -ID_INLINE idVec3& mat3_t::operator[]( int index ) { - assert( ( index >= 0 ) && ( index < 3 ) ); - return mat[ index ]; -} - -ID_INLINE idVec3 mat3_t::operator*( const idVec3 &vec ) const { - return idVec3( - mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, - mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, - mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); -} - -ID_INLINE mat3_t mat3_t::operator*( const mat3_t &a ) const { - return mat3_t( - mat[0].x * a[0].x + mat[0].y * a[1].x + mat[0].z * a[2].x, - mat[0].x * a[0].y + mat[0].y * a[1].y + mat[0].z * a[2].y, - mat[0].x * a[0].z + mat[0].y * a[1].z + mat[0].z * a[2].z, - mat[1].x * a[0].x + mat[1].y * a[1].x + mat[1].z * a[2].x, - mat[1].x * a[0].y + mat[1].y * a[1].y + mat[1].z * a[2].y, - mat[1].x * a[0].z + mat[1].y * a[1].z + mat[1].z * a[2].z, - mat[2].x * a[0].x + mat[2].y * a[1].x + mat[2].z * a[2].x, - mat[2].x * a[0].y + mat[2].y * a[1].y + mat[2].z * a[2].y, - mat[2].x * a[0].z + mat[2].y * a[1].z + mat[2].z * a[2].z ); -} - -ID_INLINE mat3_t mat3_t::operator*( float a ) const { - return mat3_t( - mat[0].x * a, mat[0].y * a, mat[0].z * a, - mat[1].x * a, mat[1].y * a, mat[1].z * a, - mat[2].x * a, mat[2].y * a, mat[2].z * a ); -} - -ID_INLINE mat3_t mat3_t::operator+( mat3_t const &a ) const { - return mat3_t( - mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z, - mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z, - mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z ); -} - -ID_INLINE mat3_t mat3_t::operator-( mat3_t const &a ) const { - return mat3_t( - mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z, - mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z, - mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z ); -} - -ID_INLINE idVec3 operator*( const idVec3 &vec, const mat3_t &mat ) { - return idVec3( - mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, - mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, - mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); -} - -ID_INLINE mat3_t operator*( float a, mat3_t const &b ) { - return mat3_t( - b[0].x * a, b[0].y * a, b[0].z * a, - b[1].x * a, b[1].y * a, b[1].z * a, - b[2].x * a, b[2].y * a, b[2].z * a ); -} - -ID_INLINE mat3_t &mat3_t::operator*=( float a ) { - mat[0].x *= a; mat[0].y *= a; mat[0].z *= a; - mat[1].x *= a; mat[1].y *= a; mat[1].z *= a; - mat[2].x *= a; mat[2].y *= a; mat[2].z *= a; - - return *this; -} - -ID_INLINE mat3_t &mat3_t::operator+=( mat3_t const &a ) { - mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z; - mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z; - mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z; - - return *this; -} - -ID_INLINE mat3_t &mat3_t::operator-=( mat3_t const &a ) { - mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z; - mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z; - mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z; - - return *this; -} - -ID_INLINE void mat3_t::OrthoNormalize( void ) { - mat[ 0 ].Normalize(); - mat[ 2 ].Cross( mat[ 0 ], mat[ 1 ] ); - mat[ 2 ].Normalize(); - mat[ 1 ].Cross( mat[ 2 ], mat[ 0 ] ); - mat[ 1 ].Normalize(); -} - -ID_INLINE void mat3_t::Identity( void ) { - mat[ 0 ].x = 1.f; mat[ 0 ].y = 0.f; mat[ 0 ].z = 0.f; - mat[ 1 ].x = 0.f; mat[ 1 ].y = 1.f; mat[ 1 ].z = 0.f; - mat[ 2 ].x = 0.f; mat[ 2 ].y = 0.f; mat[ 2 ].z = 1.f; -} - -ID_INLINE void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ) { - dst[0].x = inv[0].x * b[0].x + inv[1].x * b[1].x + inv[2].x * b[2].x; - dst[0].y = inv[0].x * b[0].y + inv[1].x * b[1].y + inv[2].x * b[2].y; - dst[0].z = inv[0].x * b[0].z + inv[1].x * b[1].z + inv[2].x * b[2].z; - dst[1].x = inv[0].y * b[0].x + inv[1].y * b[1].x + inv[2].y * b[2].x; - dst[1].y = inv[0].y * b[0].y + inv[1].y * b[1].y + inv[2].y * b[2].y; - dst[1].z = inv[0].y * b[0].z + inv[1].y * b[1].z + inv[2].y * b[2].z; - dst[2].x = inv[0].z * b[0].x + inv[1].z * b[1].x + inv[2].z * b[2].x; - dst[2].y = inv[0].z * b[0].y + inv[1].z * b[1].y + inv[2].z * b[2].y; - dst[2].z = inv[0].z * b[0].z + inv[1].z * b[1].z + inv[2].z * b[2].z; -} - -ID_INLINE mat3_t SkewSymmetric( idVec3 const &src ) { - return mat3_t( 0.0f, -src.z, src.y, src.z, 0.0f, -src.x, -src.y, src.x, 0.0f ); -} - -extern mat3_t mat3_default; - -#endif /* !__MATH_MATRIX_H__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __MATH_MATRIX_H__ +#define __MATH_MATRIX_H__ + +#include <string.h> +#include "math_vector.h" + +#ifndef ID_INLINE +#ifdef _WIN32 +#define ID_INLINE __inline +#else +#define ID_INLINE inline +#endif +#endif + +class quat_t; +class angles_t; + +class mat3_t { +public: + idVec3 mat[ 3 ]; + + mat3_t(); + mat3_t( float src[ 3 ][ 3 ] ); + mat3_t( idVec3 const &x, idVec3 const &y, idVec3 const &z ); + mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ); + + friend void toMatrix( quat_t const &src, mat3_t &dst ); + friend void toMatrix( angles_t const &src, mat3_t &dst ); + friend void toMatrix( idVec3 const &src, mat3_t &dst ); + + idVec3 operator[]( int index ) const; + idVec3 &operator[]( int index ); + + idVec3 operator*( const idVec3 &vec ) const; + mat3_t operator*( const mat3_t &a ) const; + mat3_t operator*( float a ) const; + mat3_t operator+( mat3_t const &a ) const; + mat3_t operator-( mat3_t const &a ) const; + + friend idVec3 operator*( const idVec3 &vec, const mat3_t &mat ); + friend mat3_t operator*( float a, mat3_t const &b ); + + mat3_t &operator*=( float a ); + mat3_t &operator+=( mat3_t const &a ); + mat3_t &operator-=( mat3_t const &a ); + + void Clear( void ); + + void ProjectVector( const idVec3 &src, idVec3 &dst ) const; + void UnprojectVector( const idVec3 &src, idVec3 &dst ) const; + + void OrthoNormalize( void ); + void Transpose( mat3_t &matrix ); + void Transpose( void ); + mat3_t Inverse( void ) const; + void Identity( void ); + + friend void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ); + friend mat3_t SkewSymmetric( idVec3 const &src ); +}; + +ID_INLINE mat3_t::mat3_t() { +} + +ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) { + memcpy( mat, src, sizeof( src ) ); +} + +ID_INLINE mat3_t::mat3_t( idVec3 const &x, idVec3 const &y, idVec3 const &z ) { + mat[ 0 ].x = x.x; mat[ 0 ].y = x.y; mat[ 0 ].z = x.z; + mat[ 1 ].x = y.x; mat[ 1 ].y = y.y; mat[ 1 ].z = y.z; + mat[ 2 ].x = z.x; mat[ 2 ].y = z.y; mat[ 2 ].z = z.z; +} + +ID_INLINE mat3_t::mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ) { + mat[ 0 ].x = xx; mat[ 0 ].y = xy; mat[ 0 ].z = xz; + mat[ 1 ].x = yx; mat[ 1 ].y = yy; mat[ 1 ].z = yz; + mat[ 2 ].x = zx; mat[ 2 ].y = zy; mat[ 2 ].z = zz; +} + +ID_INLINE idVec3 mat3_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 3 ) ); + return mat[ index ]; +} + +ID_INLINE idVec3& mat3_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 3 ) ); + return mat[ index ]; +} + +ID_INLINE idVec3 mat3_t::operator*( const idVec3 &vec ) const { + return idVec3( + mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, + mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, + mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); +} + +ID_INLINE mat3_t mat3_t::operator*( const mat3_t &a ) const { + return mat3_t( + mat[0].x * a[0].x + mat[0].y * a[1].x + mat[0].z * a[2].x, + mat[0].x * a[0].y + mat[0].y * a[1].y + mat[0].z * a[2].y, + mat[0].x * a[0].z + mat[0].y * a[1].z + mat[0].z * a[2].z, + mat[1].x * a[0].x + mat[1].y * a[1].x + mat[1].z * a[2].x, + mat[1].x * a[0].y + mat[1].y * a[1].y + mat[1].z * a[2].y, + mat[1].x * a[0].z + mat[1].y * a[1].z + mat[1].z * a[2].z, + mat[2].x * a[0].x + mat[2].y * a[1].x + mat[2].z * a[2].x, + mat[2].x * a[0].y + mat[2].y * a[1].y + mat[2].z * a[2].y, + mat[2].x * a[0].z + mat[2].y * a[1].z + mat[2].z * a[2].z ); +} + +ID_INLINE mat3_t mat3_t::operator*( float a ) const { + return mat3_t( + mat[0].x * a, mat[0].y * a, mat[0].z * a, + mat[1].x * a, mat[1].y * a, mat[1].z * a, + mat[2].x * a, mat[2].y * a, mat[2].z * a ); +} + +ID_INLINE mat3_t mat3_t::operator+( mat3_t const &a ) const { + return mat3_t( + mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z, + mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z, + mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z ); +} + +ID_INLINE mat3_t mat3_t::operator-( mat3_t const &a ) const { + return mat3_t( + mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z, + mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z, + mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z ); +} + +ID_INLINE idVec3 operator*( const idVec3 &vec, const mat3_t &mat ) { + return idVec3( + mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z, + mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z, + mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z ); +} + +ID_INLINE mat3_t operator*( float a, mat3_t const &b ) { + return mat3_t( + b[0].x * a, b[0].y * a, b[0].z * a, + b[1].x * a, b[1].y * a, b[1].z * a, + b[2].x * a, b[2].y * a, b[2].z * a ); +} + +ID_INLINE mat3_t &mat3_t::operator*=( float a ) { + mat[0].x *= a; mat[0].y *= a; mat[0].z *= a; + mat[1].x *= a; mat[1].y *= a; mat[1].z *= a; + mat[2].x *= a; mat[2].y *= a; mat[2].z *= a; + + return *this; +} + +ID_INLINE mat3_t &mat3_t::operator+=( mat3_t const &a ) { + mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z; + mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z; + mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z; + + return *this; +} + +ID_INLINE mat3_t &mat3_t::operator-=( mat3_t const &a ) { + mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z; + mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z; + mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z; + + return *this; +} + +ID_INLINE void mat3_t::OrthoNormalize( void ) { + mat[ 0 ].Normalize(); + mat[ 2 ].Cross( mat[ 0 ], mat[ 1 ] ); + mat[ 2 ].Normalize(); + mat[ 1 ].Cross( mat[ 2 ], mat[ 0 ] ); + mat[ 1 ].Normalize(); +} + +ID_INLINE void mat3_t::Identity( void ) { + mat[ 0 ].x = 1.f; mat[ 0 ].y = 0.f; mat[ 0 ].z = 0.f; + mat[ 1 ].x = 0.f; mat[ 1 ].y = 1.f; mat[ 1 ].z = 0.f; + mat[ 2 ].x = 0.f; mat[ 2 ].y = 0.f; mat[ 2 ].z = 1.f; +} + +ID_INLINE void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ) { + dst[0].x = inv[0].x * b[0].x + inv[1].x * b[1].x + inv[2].x * b[2].x; + dst[0].y = inv[0].x * b[0].y + inv[1].x * b[1].y + inv[2].x * b[2].y; + dst[0].z = inv[0].x * b[0].z + inv[1].x * b[1].z + inv[2].x * b[2].z; + dst[1].x = inv[0].y * b[0].x + inv[1].y * b[1].x + inv[2].y * b[2].x; + dst[1].y = inv[0].y * b[0].y + inv[1].y * b[1].y + inv[2].y * b[2].y; + dst[1].z = inv[0].y * b[0].z + inv[1].y * b[1].z + inv[2].y * b[2].z; + dst[2].x = inv[0].z * b[0].x + inv[1].z * b[1].x + inv[2].z * b[2].x; + dst[2].y = inv[0].z * b[0].y + inv[1].z * b[1].y + inv[2].z * b[2].y; + dst[2].z = inv[0].z * b[0].z + inv[1].z * b[1].z + inv[2].z * b[2].z; +} + +ID_INLINE mat3_t SkewSymmetric( idVec3 const &src ) { + return mat3_t( 0.0f, -src.z, src.y, src.z, 0.0f, -src.x, -src.y, src.x, 0.0f ); +} + +extern mat3_t mat3_default; + +#endif /* !__MATH_MATRIX_H__ */ diff --git a/libs/splines/math_quaternion.h b/libs/splines/math_quaternion.h index 6ff2c1ee..1d2e2907 100644 --- a/libs/splines/math_quaternion.h +++ b/libs/splines/math_quaternion.h @@ -1,190 +1,190 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __MATH_QUATERNION_H__ -#define __MATH_QUATERNION_H__ - -#include <assert.h> -#include <math.h> - -class idVec3_t; -class angles_t; -class mat3_t; - -class quat_t { -public: - float x; - float y; - float z; - float w; - - quat_t(); - quat_t( float x, float y, float z, float w ); - - friend void toQuat( idVec3_t &src, quat_t &dst ); - friend void toQuat( angles_t &src, quat_t &dst ); - friend void toQuat( mat3_t &src, quat_t &dst ); - - float *vec4( void ); - - float operator[]( int index ) const; - float &operator[]( int index ); - - void set( float x, float y, float z, float w ); - - void operator=( quat_t a ); - - friend quat_t operator+( quat_t a, quat_t b ); - quat_t &operator+=( quat_t a ); - - friend quat_t operator-( quat_t a, quat_t b ); - quat_t &operator-=( quat_t a ); - - friend quat_t operator*( quat_t a, float b ); - friend quat_t operator*( float a, quat_t b ); - quat_t &operator*=( float a ); - - friend int operator==( quat_t a, quat_t b ); - friend int operator!=( quat_t a, quat_t b ); - - float Length( void ); - quat_t &Normalize( void ); - - quat_t operator-(); -}; - -inline quat_t::quat_t() { -} - -inline quat_t::quat_t( float x, float y, float z, float w ) { - this->x = x; - this->y = y; - this->z = z; - this->w = w; -} - -inline float *quat_t::vec4( void ) { - return &x; -} - -inline float quat_t::operator[]( int index ) const { - assert( ( index >= 0 ) && ( index < 4 ) ); - return ( &x )[ index ]; -} - -inline float& quat_t::operator[]( int index ) { - assert( ( index >= 0 ) && ( index < 4 ) ); - return ( &x )[ index ]; -} - -inline void quat_t::set( float x, float y, float z, float w ) { - this->x = x; - this->y = y; - this->z = z; - this->w = w; -} - -inline void quat_t::operator=( quat_t a ) { - x = a.x; - y = a.y; - z = a.z; - w = a.w; -} - -inline quat_t operator+( quat_t a, quat_t b ) { - return quat_t( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); -} - -inline quat_t& quat_t::operator+=( quat_t a ) { - x += a.x; - y += a.y; - z += a.z; - w += a.w; - - return *this; -} - -inline quat_t operator-( quat_t a, quat_t b ) { - return quat_t( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); -} - -inline quat_t& quat_t::operator-=( quat_t a ) { - x -= a.x; - y -= a.y; - z -= a.z; - w -= a.w; - - return *this; -} - -inline quat_t operator*( quat_t a, float b ) { - return quat_t( a.x * b, a.y * b, a.z * b, a.w * b ); -} - -inline quat_t operator*( float a, quat_t b ) { - return b * a; -} - -inline quat_t& quat_t::operator*=( float a ) { - x *= a; - y *= a; - z *= a; - w *= a; - - return *this; -} - -inline int operator==( quat_t a, quat_t b ) { - return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) ); -} - -inline int operator!=( quat_t a, quat_t b ) { - return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); -} - -inline float quat_t::Length( void ) { - float length; - - length = x * x + y * y + z * z + w * w; - return ( float )sqrt( length ); -} - -inline quat_t& quat_t::Normalize( void ) { - float length; - float ilength; - - length = this->Length(); - if ( length ) { - ilength = 1 / length; - x *= ilength; - y *= ilength; - z *= ilength; - w *= ilength; - } - - return *this; -} - -inline quat_t quat_t::operator-() { - return quat_t( -x, -y, -z, -w ); -} - -#endif /* !__MATH_QUATERNION_H__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __MATH_QUATERNION_H__ +#define __MATH_QUATERNION_H__ + +#include <assert.h> +#include <math.h> + +class idVec3_t; +class angles_t; +class mat3_t; + +class quat_t { +public: + float x; + float y; + float z; + float w; + + quat_t(); + quat_t( float x, float y, float z, float w ); + + friend void toQuat( idVec3_t &src, quat_t &dst ); + friend void toQuat( angles_t &src, quat_t &dst ); + friend void toQuat( mat3_t &src, quat_t &dst ); + + float *vec4( void ); + + float operator[]( int index ) const; + float &operator[]( int index ); + + void set( float x, float y, float z, float w ); + + void operator=( quat_t a ); + + friend quat_t operator+( quat_t a, quat_t b ); + quat_t &operator+=( quat_t a ); + + friend quat_t operator-( quat_t a, quat_t b ); + quat_t &operator-=( quat_t a ); + + friend quat_t operator*( quat_t a, float b ); + friend quat_t operator*( float a, quat_t b ); + quat_t &operator*=( float a ); + + friend int operator==( quat_t a, quat_t b ); + friend int operator!=( quat_t a, quat_t b ); + + float Length( void ); + quat_t &Normalize( void ); + + quat_t operator-(); +}; + +inline quat_t::quat_t() { +} + +inline quat_t::quat_t( float x, float y, float z, float w ) { + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +inline float *quat_t::vec4( void ) { + return &x; +} + +inline float quat_t::operator[]( int index ) const { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; +} + +inline float& quat_t::operator[]( int index ) { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; +} + +inline void quat_t::set( float x, float y, float z, float w ) { + this->x = x; + this->y = y; + this->z = z; + this->w = w; +} + +inline void quat_t::operator=( quat_t a ) { + x = a.x; + y = a.y; + z = a.z; + w = a.w; +} + +inline quat_t operator+( quat_t a, quat_t b ) { + return quat_t( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); +} + +inline quat_t& quat_t::operator+=( quat_t a ) { + x += a.x; + y += a.y; + z += a.z; + w += a.w; + + return *this; +} + +inline quat_t operator-( quat_t a, quat_t b ) { + return quat_t( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); +} + +inline quat_t& quat_t::operator-=( quat_t a ) { + x -= a.x; + y -= a.y; + z -= a.z; + w -= a.w; + + return *this; +} + +inline quat_t operator*( quat_t a, float b ) { + return quat_t( a.x * b, a.y * b, a.z * b, a.w * b ); +} + +inline quat_t operator*( float a, quat_t b ) { + return b * a; +} + +inline quat_t& quat_t::operator*=( float a ) { + x *= a; + y *= a; + z *= a; + w *= a; + + return *this; +} + +inline int operator==( quat_t a, quat_t b ) { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) ); +} + +inline int operator!=( quat_t a, quat_t b ) { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); +} + +inline float quat_t::Length( void ) { + float length; + + length = x * x + y * y + z * z + w * w; + return ( float )sqrt( length ); +} + +inline quat_t& quat_t::Normalize( void ) { + float length; + float ilength; + + length = this->Length(); + if ( length ) { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + w *= ilength; + } + + return *this; +} + +inline quat_t quat_t::operator-() { + return quat_t( -x, -y, -z, -w ); +} + +#endif /* !__MATH_QUATERNION_H__ */ diff --git a/libs/splines/math_vector.h b/libs/splines/math_vector.h index 6e1f765a..60e86a5f 100644 --- a/libs/splines/math_vector.h +++ b/libs/splines/math_vector.h @@ -1,574 +1,574 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __MATH_VECTOR_H__ -#define __MATH_VECTOR_H__ - -#ifdef _WIN32 -#pragma warning(disable : 4244) -#endif - -#include <math.h> -#include <assert.h> - -//#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 VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) - -//#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];} - - -//#include "util_heap.h" - -#ifndef EQUAL_EPSILON -#define EQUAL_EPSILON 0.001 -#endif - -float Q_fabs( float f ); - -#ifndef ID_INLINE -#ifdef _WIN32 -#define ID_INLINE __inline -#else -#define ID_INLINE inline -#endif -#endif - -// if this is defined, vec3 will take four elements, which may allow -// easier SIMD optimizations -//#define FAT_VEC3 -//#ifdef __ppc__ -//#pragma align(16) -//#endif - -class angles_t; -#ifdef __ppc__ -// Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, -// runs *much* faster than calling sqrt(). We'll use two Newton-Raphson -// refinement steps to get bunch more precision in the 1/sqrt() value for very little cost. -// We'll then multiply 1/sqrt times the original value to get the sqrt. -// This is about 12.4 times faster than sqrt() and according to my testing (not exhaustive) -// it returns fairly accurate results (error below 1.0e-5 up to 100000.0 in 0.1 increments). - -static inline float idSqrt(float x) { - const float half = 0.5; - const float one = 1.0; - float B, y0, y1; - - // This'll NaN if it hits frsqrte. Handle both +0.0 and -0.0 - if (fabs(x) == 0.0) - return x; - B = x; - -#ifdef __GNUC__ - asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); -#else - y0 = __frsqrte(B); -#endif - /* First refinement step */ - - y1 = y0 + half*y0*(one - B*y0*y0); - - /* Second refinement step -- copy the output of the last step to the input of this step */ - - y0 = y1; - y1 = y0 + half*y0*(one - B*y0*y0); - - /* Get sqrt(x) from x * 1/sqrt(x) */ - return x * y1; -} -#else -static inline double idSqrt(double x) { - return sqrt(x); -} -#endif - - -//class idVec3 : public idHeap<idVec3> { -class idVec3 { -public: -#ifndef FAT_VEC3 - float x,y,z; -#else - float x,y,z,dist; -#endif - -#ifndef FAT_VEC3 - idVec3() {}; -#else - idVec3() {dist = 0.0f;}; -#endif - idVec3( const float x, const float y, const float z ); - - operator float *(); - - float operator[]( const int index ) const; - float &operator[]( const int index ); - - void set( const float x, const float y, const float z ); - - idVec3 operator-() const; - - idVec3 &operator=( const idVec3 &a ); - - float operator*( const idVec3 &a ) const; - idVec3 operator*( const float a ) const; - friend idVec3 operator*( float a, idVec3 b ); - - idVec3 operator+( const idVec3 &a ) const; - idVec3 operator-( const idVec3 &a ) const; - - idVec3 &operator+=( const idVec3 &a ); - idVec3 &operator-=( const idVec3 &a ); - idVec3 &operator*=( const float a ); - - int operator==( const idVec3 &a ) const; - int operator!=( const idVec3 &a ) const; - - idVec3 Cross( const idVec3 &a ) const; - idVec3 &Cross( const idVec3 &a, const idVec3 &b ); - - float Length( void ) const; - float Normalize( void ); - - void Zero( void ); - void Snap( void ); - void SnapTowards( const idVec3 &to ); - - float toYaw( void ); - float toPitch( void ); - angles_t toAngles( void ); - friend idVec3 LerpVector( const idVec3 &w1, const idVec3 &w2, const float t ); - - char *string( void ); -}; - -extern idVec3 vec_zero; - -ID_INLINE idVec3::idVec3( const float x, const float y, const float z ) { - this->x = x; - this->y = y; - this->z = z; -#ifdef FAT_VEC3 - this->dist = 0.0f; -#endif -} - -ID_INLINE float idVec3::operator[]( const int index ) const { - return ( &x )[ index ]; -} - -ID_INLINE float &idVec3::operator[]( const int index ) { - return ( &x )[ index ]; -} - -ID_INLINE idVec3::operator float *( void ) { - return &x; -} - -ID_INLINE idVec3 idVec3::operator-() const { - return idVec3( -x, -y, -z ); -} - -ID_INLINE idVec3 &idVec3::operator=( const idVec3 &a ) { - x = a.x; - y = a.y; - z = a.z; - - return *this; -} - -ID_INLINE void idVec3::set( const float x, const float y, const float z ) { - this->x = x; - this->y = y; - this->z = z; -} - -ID_INLINE idVec3 idVec3::operator-( const idVec3 &a ) const { - return idVec3( x - a.x, y - a.y, z - a.z ); -} - -ID_INLINE float idVec3::operator*( const idVec3 &a ) const { - return x * a.x + y * a.y + z * a.z; -} - -ID_INLINE idVec3 idVec3::operator*( const float a ) const { - return idVec3( x * a, y * a, z * a ); -} - -ID_INLINE idVec3 operator*( const float a, const idVec3 b ) { - return idVec3( b.x * a, b.y * a, b.z * a ); -} - -ID_INLINE idVec3 idVec3::operator+( const idVec3 &a ) const { - return idVec3( x + a.x, y + a.y, z + a.z ); -} - -ID_INLINE idVec3 &idVec3::operator+=( const idVec3 &a ) { - x += a.x; - y += a.y; - z += a.z; - - return *this; -} - -ID_INLINE idVec3 &idVec3::operator-=( const idVec3 &a ) { - x -= a.x; - y -= a.y; - z -= a.z; - - return *this; -} - -ID_INLINE idVec3 &idVec3::operator*=( const float a ) { - x *= a; - y *= a; - z *= a; - - return *this; -} - -ID_INLINE int idVec3::operator==( const idVec3 &a ) const { - if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { - return false; - } - - if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { - return false; - } - - if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { - return false; - } - - return true; -} - -ID_INLINE int idVec3::operator!=( const idVec3 &a ) const { - if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { - return true; - } - - if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { - return true; - } - - if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { - return true; - } - - return false; -} - -ID_INLINE idVec3 idVec3::Cross( const idVec3 &a ) const { - return idVec3( y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x ); -} - -ID_INLINE idVec3 &idVec3::Cross( const idVec3 &a, const idVec3 &b ) { - x = a.y * b.z - a.z * b.y; - y = a.z * b.x - a.x * b.z; - z = a.x * b.y - a.y * b.x; - - return *this; -} - -ID_INLINE float idVec3::Length( void ) const { - float length; - - length = x * x + y * y + z * z; - return ( float )idSqrt( length ); -} - -ID_INLINE float idVec3::Normalize( void ) { - float length; - float ilength; - - length = this->Length(); - if ( length ) { - ilength = 1.0f / length; - x *= ilength; - y *= ilength; - z *= ilength; - } - - return length; -} - -ID_INLINE void idVec3::Zero( void ) { - x = 0.0f; - y = 0.0f; - z = 0.0f; -} - -ID_INLINE void idVec3::Snap( void ) { - x = float( int( x ) ); - y = float( int( y ) ); - z = float( int( z ) ); -} - -/* -====================== -SnapTowards - -Round a vector to integers for more efficient network -transmission, but make sure that it rounds towards a given point -rather than blindly truncating. This prevents it from truncating -into a wall. -====================== -*/ -ID_INLINE void idVec3::SnapTowards( const idVec3 &to ) { - if ( to.x <= x ) { - x = float( int( x ) ); - } else { - x = float( int( x ) + 1 ); - } - - if ( to.y <= y ) { - y = float( int( y ) ); - } else { - y = float( int( y ) + 1 ); - } - - if ( to.z <= z ) { - z = float( int( z ) ); - } else { - z = float( int( z ) + 1 ); - } -} - -//=============================================================== - -class Bounds { -public: - idVec3 b[2]; - - Bounds(); - Bounds( const idVec3 &mins, const idVec3 &maxs ); - - void Clear(); - void Zero(); - float Radius(); // radius from origin, not from center - idVec3 Center(); - void AddPoint( const idVec3 &v ); - void AddBounds( const Bounds &bb ); - bool IsCleared(); - bool ContainsPoint( const idVec3 &p ); - bool IntersectsBounds( const Bounds &b2 ); // touching is NOT intersecting -}; - -extern Bounds boundsZero; - -ID_INLINE Bounds::Bounds(){ -} - -ID_INLINE bool Bounds::IsCleared() { - return b[0][0] > b[1][0]; -} - -ID_INLINE bool Bounds::ContainsPoint( const idVec3 &p ) { - if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2] - || p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) { - return false; - } - return true; -} - -ID_INLINE bool Bounds::IntersectsBounds( const Bounds &b2 ) { - if ( b2.b[1][0] < b[0][0] || b2.b[1][1] < b[0][1] || b2.b[1][2] < b[0][2] - || b2.b[0][0] > b[1][0] || b2.b[0][1] > b[1][1] || b2.b[0][2] > b[1][2] ) { - return false; - } - return true; -} - -ID_INLINE Bounds::Bounds( const idVec3 &mins, const idVec3 &maxs ) { - b[0] = mins; - b[1] = maxs; -} - -ID_INLINE idVec3 Bounds::Center() { - return idVec3( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f ); -} - -ID_INLINE void Bounds::Clear() { - b[0][0] = b[0][1] = b[0][2] = 99999; - b[1][0] = b[1][1] = b[1][2] = -99999; -} - -ID_INLINE void Bounds::Zero() { - b[0][0] = b[0][1] = b[0][2] = - b[1][0] = b[1][1] = b[1][2] = 0; -} - -ID_INLINE void Bounds::AddPoint( const idVec3 &v ) { - if ( v[0] < b[0][0]) { - b[0][0] = v[0]; - } - if ( v[0] > b[1][0]) { - b[1][0] = v[0]; - } - if ( v[1] < b[0][1] ) { - b[0][1] = v[1]; - } - if ( v[1] > b[1][1]) { - b[1][1] = v[1]; - } - if ( v[2] < b[0][2] ) { - b[0][2] = v[2]; - } - if ( v[2] > b[1][2]) { - b[1][2] = v[2]; - } -} - - -ID_INLINE void Bounds::AddBounds( const Bounds &bb ) { - if ( bb.b[0][0] < b[0][0]) { - b[0][0] = bb.b[0][0]; - } - if ( bb.b[0][1] < b[0][1]) { - b[0][1] = bb.b[0][1]; - } - if ( bb.b[0][2] < b[0][2]) { - b[0][2] = bb.b[0][2]; - } - - if ( bb.b[1][0] > b[1][0]) { - b[1][0] = bb.b[1][0]; - } - if ( bb.b[1][1] > b[1][1]) { - b[1][1] = bb.b[1][1]; - } - if ( bb.b[1][2] > b[1][2]) { - b[1][2] = bb.b[1][2]; - } -} - -ID_INLINE float Bounds::Radius( ) { - int i; - float total; - float a, aa; - - total = 0; - for (i=0 ; i<3 ; i++) { - a = (float)fabs( b[0][i] ); - aa = (float)fabs( b[1][i] ); - if ( aa > a ) { - a = aa; - } - total += a * a; - } - - return (float)idSqrt( total ); -} - -//=============================================================== - - -class idVec2 { -public: - float x; - float y; - - operator float *(); - float operator[]( int index ) const; - float &operator[]( int index ); -}; - -ID_INLINE float idVec2::operator[]( int index ) const { - return ( &x )[ index ]; -} - -ID_INLINE float& idVec2::operator[]( int index ) { - return ( &x )[ index ]; -} - -ID_INLINE idVec2::operator float *( void ) { - return &x; -} - -class idVec4 : public idVec3 { -public: -#ifndef FAT_VEC3 - float dist; -#endif - idVec4(); - ~idVec4() {}; - - idVec4( float x, float y, float z, float dist ); - float operator[]( int index ) const; - float &operator[]( int index ); -}; - -ID_INLINE idVec4::idVec4() {} -ID_INLINE idVec4::idVec4( float x, float y, float z, float dist ) { - this->x = x; - this->y = y; - this->z = z; - this->dist = dist; -} - -ID_INLINE float idVec4::operator[]( int index ) const { - return ( &x )[ index ]; -} - -ID_INLINE float& idVec4::operator[]( int index ) { - return ( &x )[ index ]; -} - - -class idVec5_t : public idVec3 { -public: - float s; - float t; - float operator[]( int index ) const; - float &operator[]( int index ); -}; - - -ID_INLINE float idVec5_t::operator[]( int index ) const { - return ( &x )[ index ]; -} - -ID_INLINE float& idVec5_t::operator[]( int index ) { - return ( &x )[ index ]; -} - -#endif /* !__MATH_VECTOR_H__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __MATH_VECTOR_H__ +#define __MATH_VECTOR_H__ + +#ifdef _WIN32 +#pragma warning(disable : 4244) +#endif + +#include <math.h> +#include <assert.h> + +//#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 VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) + +//#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];} + + +//#include "util_heap.h" + +#ifndef EQUAL_EPSILON +#define EQUAL_EPSILON 0.001 +#endif + +float Q_fabs( float f ); + +#ifndef ID_INLINE +#ifdef _WIN32 +#define ID_INLINE __inline +#else +#define ID_INLINE inline +#endif +#endif + +// if this is defined, vec3 will take four elements, which may allow +// easier SIMD optimizations +//#define FAT_VEC3 +//#ifdef __ppc__ +//#pragma align(16) +//#endif + +class angles_t; +#ifdef __ppc__ +// Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction, +// runs *much* faster than calling sqrt(). We'll use two Newton-Raphson +// refinement steps to get bunch more precision in the 1/sqrt() value for very little cost. +// We'll then multiply 1/sqrt times the original value to get the sqrt. +// This is about 12.4 times faster than sqrt() and according to my testing (not exhaustive) +// it returns fairly accurate results (error below 1.0e-5 up to 100000.0 in 0.1 increments). + +static inline float idSqrt(float x) { + const float half = 0.5; + const float one = 1.0; + float B, y0, y1; + + // This'll NaN if it hits frsqrte. Handle both +0.0 and -0.0 + if (fabs(x) == 0.0) + return x; + B = x; + +#ifdef __GNUC__ + asm("frsqrte %0,%1" : "=f" (y0) : "f" (B)); +#else + y0 = __frsqrte(B); +#endif + /* First refinement step */ + + y1 = y0 + half*y0*(one - B*y0*y0); + + /* Second refinement step -- copy the output of the last step to the input of this step */ + + y0 = y1; + y1 = y0 + half*y0*(one - B*y0*y0); + + /* Get sqrt(x) from x * 1/sqrt(x) */ + return x * y1; +} +#else +static inline double idSqrt(double x) { + return sqrt(x); +} +#endif + + +//class idVec3 : public idHeap<idVec3> { +class idVec3 { +public: +#ifndef FAT_VEC3 + float x,y,z; +#else + float x,y,z,dist; +#endif + +#ifndef FAT_VEC3 + idVec3() {}; +#else + idVec3() {dist = 0.0f;}; +#endif + idVec3( const float x, const float y, const float z ); + + operator float *(); + + float operator[]( const int index ) const; + float &operator[]( const int index ); + + void set( const float x, const float y, const float z ); + + idVec3 operator-() const; + + idVec3 &operator=( const idVec3 &a ); + + float operator*( const idVec3 &a ) const; + idVec3 operator*( const float a ) const; + friend idVec3 operator*( float a, idVec3 b ); + + idVec3 operator+( const idVec3 &a ) const; + idVec3 operator-( const idVec3 &a ) const; + + idVec3 &operator+=( const idVec3 &a ); + idVec3 &operator-=( const idVec3 &a ); + idVec3 &operator*=( const float a ); + + int operator==( const idVec3 &a ) const; + int operator!=( const idVec3 &a ) const; + + idVec3 Cross( const idVec3 &a ) const; + idVec3 &Cross( const idVec3 &a, const idVec3 &b ); + + float Length( void ) const; + float Normalize( void ); + + void Zero( void ); + void Snap( void ); + void SnapTowards( const idVec3 &to ); + + float toYaw( void ); + float toPitch( void ); + angles_t toAngles( void ); + friend idVec3 LerpVector( const idVec3 &w1, const idVec3 &w2, const float t ); + + char *string( void ); +}; + +extern idVec3 vec_zero; + +ID_INLINE idVec3::idVec3( const float x, const float y, const float z ) { + this->x = x; + this->y = y; + this->z = z; +#ifdef FAT_VEC3 + this->dist = 0.0f; +#endif +} + +ID_INLINE float idVec3::operator[]( const int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float &idVec3::operator[]( const int index ) { + return ( &x )[ index ]; +} + +ID_INLINE idVec3::operator float *( void ) { + return &x; +} + +ID_INLINE idVec3 idVec3::operator-() const { + return idVec3( -x, -y, -z ); +} + +ID_INLINE idVec3 &idVec3::operator=( const idVec3 &a ) { + x = a.x; + y = a.y; + z = a.z; + + return *this; +} + +ID_INLINE void idVec3::set( const float x, const float y, const float z ) { + this->x = x; + this->y = y; + this->z = z; +} + +ID_INLINE idVec3 idVec3::operator-( const idVec3 &a ) const { + return idVec3( x - a.x, y - a.y, z - a.z ); +} + +ID_INLINE float idVec3::operator*( const idVec3 &a ) const { + return x * a.x + y * a.y + z * a.z; +} + +ID_INLINE idVec3 idVec3::operator*( const float a ) const { + return idVec3( x * a, y * a, z * a ); +} + +ID_INLINE idVec3 operator*( const float a, const idVec3 b ) { + return idVec3( b.x * a, b.y * a, b.z * a ); +} + +ID_INLINE idVec3 idVec3::operator+( const idVec3 &a ) const { + return idVec3( x + a.x, y + a.y, z + a.z ); +} + +ID_INLINE idVec3 &idVec3::operator+=( const idVec3 &a ) { + x += a.x; + y += a.y; + z += a.z; + + return *this; +} + +ID_INLINE idVec3 &idVec3::operator-=( const idVec3 &a ) { + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; +} + +ID_INLINE idVec3 &idVec3::operator*=( const float a ) { + x *= a; + y *= a; + z *= a; + + return *this; +} + +ID_INLINE int idVec3::operator==( const idVec3 &a ) const { + if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { + return false; + } + + if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { + return false; + } + + if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { + return false; + } + + return true; +} + +ID_INLINE int idVec3::operator!=( const idVec3 &a ) const { + if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) { + return true; + } + + if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) { + return true; + } + + if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) { + return true; + } + + return false; +} + +ID_INLINE idVec3 idVec3::Cross( const idVec3 &a ) const { + return idVec3( y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x ); +} + +ID_INLINE idVec3 &idVec3::Cross( const idVec3 &a, const idVec3 &b ) { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; +} + +ID_INLINE float idVec3::Length( void ) const { + float length; + + length = x * x + y * y + z * z; + return ( float )idSqrt( length ); +} + +ID_INLINE float idVec3::Normalize( void ) { + float length; + float ilength; + + length = this->Length(); + if ( length ) { + ilength = 1.0f / length; + x *= ilength; + y *= ilength; + z *= ilength; + } + + return length; +} + +ID_INLINE void idVec3::Zero( void ) { + x = 0.0f; + y = 0.0f; + z = 0.0f; +} + +ID_INLINE void idVec3::Snap( void ) { + x = float( int( x ) ); + y = float( int( y ) ); + z = float( int( z ) ); +} + +/* +====================== +SnapTowards + +Round a vector to integers for more efficient network +transmission, but make sure that it rounds towards a given point +rather than blindly truncating. This prevents it from truncating +into a wall. +====================== +*/ +ID_INLINE void idVec3::SnapTowards( const idVec3 &to ) { + if ( to.x <= x ) { + x = float( int( x ) ); + } else { + x = float( int( x ) + 1 ); + } + + if ( to.y <= y ) { + y = float( int( y ) ); + } else { + y = float( int( y ) + 1 ); + } + + if ( to.z <= z ) { + z = float( int( z ) ); + } else { + z = float( int( z ) + 1 ); + } +} + +//=============================================================== + +class Bounds { +public: + idVec3 b[2]; + + Bounds(); + Bounds( const idVec3 &mins, const idVec3 &maxs ); + + void Clear(); + void Zero(); + float Radius(); // radius from origin, not from center + idVec3 Center(); + void AddPoint( const idVec3 &v ); + void AddBounds( const Bounds &bb ); + bool IsCleared(); + bool ContainsPoint( const idVec3 &p ); + bool IntersectsBounds( const Bounds &b2 ); // touching is NOT intersecting +}; + +extern Bounds boundsZero; + +ID_INLINE Bounds::Bounds(){ +} + +ID_INLINE bool Bounds::IsCleared() { + return b[0][0] > b[1][0]; +} + +ID_INLINE bool Bounds::ContainsPoint( const idVec3 &p ) { + if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2] + || p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) { + return false; + } + return true; +} + +ID_INLINE bool Bounds::IntersectsBounds( const Bounds &b2 ) { + if ( b2.b[1][0] < b[0][0] || b2.b[1][1] < b[0][1] || b2.b[1][2] < b[0][2] + || b2.b[0][0] > b[1][0] || b2.b[0][1] > b[1][1] || b2.b[0][2] > b[1][2] ) { + return false; + } + return true; +} + +ID_INLINE Bounds::Bounds( const idVec3 &mins, const idVec3 &maxs ) { + b[0] = mins; + b[1] = maxs; +} + +ID_INLINE idVec3 Bounds::Center() { + return idVec3( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f ); +} + +ID_INLINE void Bounds::Clear() { + b[0][0] = b[0][1] = b[0][2] = 99999; + b[1][0] = b[1][1] = b[1][2] = -99999; +} + +ID_INLINE void Bounds::Zero() { + b[0][0] = b[0][1] = b[0][2] = + b[1][0] = b[1][1] = b[1][2] = 0; +} + +ID_INLINE void Bounds::AddPoint( const idVec3 &v ) { + if ( v[0] < b[0][0]) { + b[0][0] = v[0]; + } + if ( v[0] > b[1][0]) { + b[1][0] = v[0]; + } + if ( v[1] < b[0][1] ) { + b[0][1] = v[1]; + } + if ( v[1] > b[1][1]) { + b[1][1] = v[1]; + } + if ( v[2] < b[0][2] ) { + b[0][2] = v[2]; + } + if ( v[2] > b[1][2]) { + b[1][2] = v[2]; + } +} + + +ID_INLINE void Bounds::AddBounds( const Bounds &bb ) { + if ( bb.b[0][0] < b[0][0]) { + b[0][0] = bb.b[0][0]; + } + if ( bb.b[0][1] < b[0][1]) { + b[0][1] = bb.b[0][1]; + } + if ( bb.b[0][2] < b[0][2]) { + b[0][2] = bb.b[0][2]; + } + + if ( bb.b[1][0] > b[1][0]) { + b[1][0] = bb.b[1][0]; + } + if ( bb.b[1][1] > b[1][1]) { + b[1][1] = bb.b[1][1]; + } + if ( bb.b[1][2] > b[1][2]) { + b[1][2] = bb.b[1][2]; + } +} + +ID_INLINE float Bounds::Radius( ) { + int i; + float total; + float a, aa; + + total = 0; + for (i=0 ; i<3 ; i++) { + a = (float)fabs( b[0][i] ); + aa = (float)fabs( b[1][i] ); + if ( aa > a ) { + a = aa; + } + total += a * a; + } + + return (float)idSqrt( total ); +} + +//=============================================================== + + +class idVec2 { +public: + float x; + float y; + + operator float *(); + float operator[]( int index ) const; + float &operator[]( int index ); +}; + +ID_INLINE float idVec2::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& idVec2::operator[]( int index ) { + return ( &x )[ index ]; +} + +ID_INLINE idVec2::operator float *( void ) { + return &x; +} + +class idVec4 : public idVec3 { +public: +#ifndef FAT_VEC3 + float dist; +#endif + idVec4(); + ~idVec4() {}; + + idVec4( float x, float y, float z, float dist ); + float operator[]( int index ) const; + float &operator[]( int index ); +}; + +ID_INLINE idVec4::idVec4() {} +ID_INLINE idVec4::idVec4( float x, float y, float z, float dist ) { + this->x = x; + this->y = y; + this->z = z; + this->dist = dist; +} + +ID_INLINE float idVec4::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& idVec4::operator[]( int index ) { + return ( &x )[ index ]; +} + + +class idVec5_t : public idVec3 { +public: + float s; + float t; + float operator[]( int index ) const; + float &operator[]( int index ); +}; + + +ID_INLINE float idVec5_t::operator[]( int index ) const { + return ( &x )[ index ]; +} + +ID_INLINE float& idVec5_t::operator[]( int index ) { + return ( &x )[ index ]; +} + +#endif /* !__MATH_VECTOR_H__ */ diff --git a/libs/splines/q_shared.h b/libs/splines/q_shared.h index 1fc7d818..60261cb4 100644 --- a/libs/splines/q_shared.h +++ b/libs/splines/q_shared.h @@ -1,796 +1,796 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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_SHARED_H -#define __Q_SHARED_H - -// q_shared.h -- included first by ALL program modules. -// these are the definitions that have no dependance on -// central system services, and can be used by any part -// of the program without any state issues. - -// A user mod should never modify this file - -#define Q3_VERSION "DOOM 0.01" - -// alignment macros for SIMD -#define ALIGN_ON -#define ALIGN_OFF - -#ifdef _WIN32 - -#pragma warning(disable : 4018) // signed/unsigned mismatch -#pragma warning(disable : 4032) -#pragma warning(disable : 4051) -#pragma warning(disable : 4057) // slightly different base types -#pragma warning(disable : 4100) // unreferenced formal parameter -#pragma warning(disable : 4115) -#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence -#pragma warning(disable : 4127) // conditional expression is constant -#pragma warning(disable : 4136) -#pragma warning(disable : 4201) -#pragma warning(disable : 4214) -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) // truncation from const double to float -#pragma warning(disable : 4310) // cast truncates constant value -#pragma warning(disable : 4514) -#pragma warning(disable : 4711) // selected for automatic inline expansion -#pragma warning(disable : 4220) // varargs matches remaining parameters - -#endif - -#include <assert.h> -#include <math.h> -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> -#include <ctype.h> -#ifdef _WIN32 // mac doesn't have malloc.h -#include <malloc.h> // for _alloca() -#endif -#ifdef _WIN32 - -//#pragma intrinsic( memset, memcpy ) - -#endif - - -// this is the define for determining if we have an asm version of a C function -#if (defined _M_IX86 || defined __i386__) && !defined __sun__ && !defined __LCC__ -#define id386 1 -#else -#define id386 0 -#endif - -// for windows fastcall option - -#define QDECL - -//======================= WIN32 DEFINES ================================= - -#ifdef _WIN32 - -#define MAC_STATIC - -#undef QDECL -#define QDECL __cdecl - -// buildstring will be incorporated into the version string -#ifdef NDEBUG -#ifdef _M_IX86 -#define CPUSTRING "win-x86" -#elif defined _M_ALPHA -#define CPUSTRING "win-AXP" -#endif -#else -#ifdef _M_IX86 -#define CPUSTRING "win-x86-debug" -#elif defined _M_ALPHA -#define CPUSTRING "win-AXP-debug" -#endif -#endif - - -#define PATH_SEP '\\' - -#endif - -//======================= MAC OS X SERVER DEFINES ===================== - -#if defined(__MACH__) && defined(__APPLE__) - -#define MAC_STATIC - -#ifdef __ppc__ -#define CPUSTRING "MacOSXS-ppc" -#elif defined __i386__ -#define CPUSTRING "MacOSXS-i386" -#else -#define CPUSTRING "MacOSXS-other" -#endif - -#define PATH_SEP '/' - -#define GAME_HARD_LINKED -#define CGAME_HARD_LINKED -#define UI_HARD_LINKED -#define _alloca alloca - -#undef ALIGN_ON -#undef ALIGN_OFF -#define ALIGN_ON #pragma align(16) -#define ALIGN_OFF #pragma align() - -#ifdef __cplusplus - extern "C" { -#endif - -void *osxAllocateMemory(long size); -void osxFreeMemory(void *pointer); - -#ifdef __cplusplus - } -#endif - -#endif - -//======================= MAC DEFINES ================================= - -#ifdef __MACOS__ - -#define MAC_STATIC static - -#define CPUSTRING "MacOS-PPC" - -#define PATH_SEP ':' - -void Sys_PumpEvents( void ); - -#endif - -#ifdef __MRC__ - -#define MAC_STATIC - -#define CPUSTRING "MacOS-PPC" - -#define PATH_SEP ':' - -void Sys_PumpEvents( void ); - -#undef QDECL -#define QDECL __cdecl - -#define _alloca alloca -#endif - -//======================= LINUX DEFINES ================================= - -// the mac compiler can't handle >32k of locals, so we -// just waste space and make big arrays static... -#ifdef __linux__ - -#define MAC_STATIC - -#ifdef __i386__ -#define CPUSTRING "linux-i386" -#elif defined __axp__ -#define CPUSTRING "linux-alpha" -#else -#define CPUSTRING "linux-other" -#endif - -#define PATH_SEP '/' - -#endif - -//============================================================= - -typedef enum {qfalse, qtrue} qboolean; - -typedef unsigned char byte; - -#define EQUAL_EPSILON 0.001 - -typedef int qhandle_t; -typedef int sfxHandle_t; -typedef int fileHandle_t; -typedef int clipHandle_t; - -typedef enum { - INVALID_JOINT = -1 -} jointHandle_t; - -#ifndef NULL -#define NULL ((void *)0) -#endif - -#define MAX_QINT 0x7fffffff -#define MIN_QINT (-MAX_QINT-1) - -#ifndef max -#define max( x, y ) ( ( ( x ) > ( y ) ) ? ( x ) : ( y ) ) -#define min( x, y ) ( ( ( x ) < ( y ) ) ? ( x ) : ( y ) ) -#endif - -#ifndef sign -#define sign( f ) ( ( f > 0 ) ? 1 : ( ( f < 0 ) ? -1 : 0 ) ) -#endif - -// angle indexes -#define PITCH 0 // up / down -#define YAW 1 // left / right -#define ROLL 2 // fall over - -// the game guarantees that no string from the network will ever -// exceed MAX_STRING_CHARS -#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString -#define MAX_STRING_TOKENS 256 // max tokens resulting from Cmd_TokenizeString -#define MAX_TOKEN_CHARS 1024 // max length of an individual token - -#define MAX_INFO_STRING 1024 -#define MAX_INFO_KEY 1024 -#define MAX_INFO_VALUE 1024 - - -#define MAX_QPATH 64 // max length of a quake game pathname -#define MAX_OSPATH 128 // max length of a filesystem pathname - -#define MAX_NAME_LENGTH 32 // max length of a client name - -// paramters for command buffer stuffing -typedef enum { - EXEC_NOW, // don't return until completed, a VM should NEVER use this, - // because some commands might cause the VM to be unloaded... - EXEC_INSERT, // insert at current position, but don't run yet - EXEC_APPEND // add to end of the command buffer (normal case) -} cbufExec_t; - - -// -// these aren't needed by any of the VMs. put in another header? -// -#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility - -#undef ERR_FATAL // malloc.h on unix - -// parameters to the main Error routine -typedef enum { - ERR_NONE, - ERR_FATAL, // exit the entire game with a popup window - ERR_DROP, // print to console and disconnect from game - ERR_DISCONNECT, // don't kill server - ERR_NEED_CD // pop up the need-cd dialog -} errorParm_t; - - -// font rendering values used by ui and cgame - -#define PROP_GAP_WIDTH 3 -#define PROP_SPACE_WIDTH 8 -#define PROP_HEIGHT 27 -#define PROP_SMALL_SIZE_SCALE 0.75 - -#define BLINK_DIVISOR 200 -#define PULSE_DIVISOR 75 - -#define UI_LEFT 0x00000000 // default -#define UI_CENTER 0x00000001 -#define UI_RIGHT 0x00000002 -#define UI_FORMATMASK 0x00000007 -#define UI_SMALLFONT 0x00000010 -#define UI_BIGFONT 0x00000020 // default -#define UI_GIANTFONT 0x00000040 -#define UI_DROPSHADOW 0x00000800 -#define UI_BLINK 0x00001000 -#define UI_INVERSE 0x00002000 -#define UI_PULSE 0x00004000 - - -/* -============================================================== - -MATHLIB - -============================================================== -*/ -#ifdef __cplusplus // so we can include this in C code -#define SIDE_FRONT 0 -#define SIDE_BACK 1 -#define SIDE_ON 2 -#define SIDE_CROSS 3 - -#define Q_PI 3.14159265358979323846 -#ifndef M_PI -#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h -#endif - -#include "math_vector.h" -#include "math_angles.h" -#include "math_matrix.h" -#include "math_quaternion.h" - -class idVec3; // for defining vectors -typedef idVec3 &vec3_p; // for passing vectors as function arguments -typedef const idVec3 &vec3_c; // for passing vectors as const function arguments - -class angles_t; // for defining angle vectors -typedef angles_t &angles_p; // for passing angles as function arguments -typedef const angles_t &angles_c; // for passing angles as const function arguments - -class mat3_t; // for defining matrices -typedef mat3_t &mat3_p; // for passing matrices as function arguments -typedef const mat3_t &mat3_c; // for passing matrices as const function arguments - - - -#define NUMVERTEXNORMALS 162 -extern idVec3 bytedirs[NUMVERTEXNORMALS]; - -// all drawing is done to a 640*480 virtual screen size -// and will be automatically scaled to the real resolution -#define SCREEN_WIDTH 640 -#define SCREEN_HEIGHT 480 - -#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH) -#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2) - -#define SMALLCHAR_WIDTH 8 -#define SMALLCHAR_HEIGHT 16 - -#define BIGCHAR_WIDTH 16 -#define BIGCHAR_HEIGHT 16 - -#define GIANTCHAR_WIDTH 32 -#define GIANTCHAR_HEIGHT 48 - -extern idVec4 colorBlack; -extern idVec4 colorRed; -extern idVec4 colorGreen; -extern idVec4 colorBlue; -extern idVec4 colorYellow; -extern idVec4 colorMagenta; -extern idVec4 colorCyan; -extern idVec4 colorWhite; -extern idVec4 colorLtGrey; -extern idVec4 colorMdGrey; -extern idVec4 colorDkGrey; - -#define Q_COLOR_ESCAPE '^' -#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) - -#define COLOR_BLACK '0' -#define COLOR_RED '1' -#define COLOR_GREEN '2' -#define COLOR_YELLOW '3' -#define COLOR_BLUE '4' -#define COLOR_CYAN '5' -#define COLOR_MAGENTA '6' -#define COLOR_WHITE '7' -#define ColorIndex(c) ( ( (c) - '0' ) & 7 ) - -#define S_COLOR_BLACK "^0" -#define S_COLOR_RED "^1" -#define S_COLOR_GREEN "^2" -#define S_COLOR_YELLOW "^3" -#define S_COLOR_BLUE "^4" -#define S_COLOR_CYAN "^5" -#define S_COLOR_MAGENTA "^6" -#define S_COLOR_WHITE "^7" - -extern idVec4 g_color_table[8]; - -#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b -#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a - -#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F ) -#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI ) - -struct cplane_s; - -extern idVec3 vec3_origin; -extern idVec4 vec4_origin; -extern mat3_t axisDefault; - -#define nanmask (255<<23) - -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) - -float Q_fabs( float f ); -float Q_rsqrt( float f ); // reciprocal square root - -#define SQRTFAST( x ) ( 1.0f / Q_rsqrt( x ) ) - -signed char ClampChar( int i ); -signed short ClampShort( int i ); - -// this isn't a real cheap function to call! -int DirToByte( const idVec3 &dir ); -void ByteToDir( int b, vec3_p dir ); - -#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 VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) - -#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];} - -float NormalizeColor( vec3_c in, vec3_p out ); - -int VectorCompare( vec3_c v1, vec3_c v2 ); -float VectorLength( vec3_c v ); -float Distance( vec3_c p1, vec3_c p2 ); -float DistanceSquared( vec3_c p1, vec3_c p2 ); -float VectorNormalize (vec3_p v); // returns vector length -void VectorNormalizeFast(vec3_p v); // does NOT return vector length, uses rsqrt approximation -float VectorNormalize2( vec3_c v, vec3_p out ); -void VectorInverse (vec3_p v); -void VectorRotate( vec3_c in, mat3_c matrix, vec3_p out ); -void VectorPolar(vec3_p v, float radius, float theta, float phi); -void VectorSnap(vec3_p v); -void Vector53Copy( const idVec5_t &in, vec3_p out); -void Vector5Scale( const idVec5_t &v, float scale, idVec5_t &out); -void Vector5Add( const idVec5_t &va, const idVec5_t &vb, idVec5_t &out); -void VectorRotate3( vec3_c vIn, vec3_c vRotation, vec3_p out); -void VectorRotate3Origin(vec3_c vIn, vec3_c vRotation, vec3_c vOrigin, vec3_p out); - - -int Q_log2(int val); - -int Q_rand( int *seed ); -float Q_random( int *seed ); -float Q_crandom( int *seed ); - -#define random() ((rand () & 0x7fff) / ((float)0x7fff)) -#define crandom() (2.0 * (random() - 0.5)) - -float Q_rint( float in ); - -void vectoangles( vec3_c value1, angles_p angles); -void AnglesToAxis( angles_c angles, mat3_p axis ); - -void AxisCopy( mat3_c in, mat3_p out ); -qboolean AxisRotated( mat3_c in ); // assumes a non-degenerate axis - -int SignbitsForNormal( vec3_c normal ); -int BoxOnPlaneSide( const Bounds &b, struct cplane_s *p ); - -float AngleMod(float a); -float LerpAngle (float from, float to, float frac); -float AngleSubtract( float a1, float a2 ); -void AnglesSubtract( angles_c v1, angles_c v2, angles_p v3 ); - -float AngleNormalize360 ( float angle ); -float AngleNormalize180 ( float angle ); -float AngleDelta ( float angle1, float angle2 ); - -qboolean PlaneFromPoints( idVec4 &plane, vec3_c a, vec3_c b, vec3_c c ); -void ProjectPointOnPlane( vec3_p dst, vec3_c p, vec3_c normal ); -void RotatePointAroundVector( vec3_p dst, vec3_c dir, vec3_c point, float degrees ); -void RotateAroundDirection( mat3_p axis, float yaw ); -void MakeNormalVectors( vec3_c forward, vec3_p right, vec3_p up ); -// perpendicular vector could be replaced by this - -int PlaneTypeForNormal( vec3_c normal ); - -void MatrixMultiply( mat3_c in1, mat3_c in2, mat3_p out ); -void MatrixInverseMultiply( mat3_c in1, mat3_c in2, mat3_p out ); // in2 is transposed during multiply -void MatrixTransformVector( vec3_c in, mat3_c matrix, vec3_p out ); -void MatrixProjectVector( vec3_c in, mat3_c matrix, vec3_p out ); // Places the vector into a new coordinate system. -void AngleVectors( angles_c angles, vec3_p forward, vec3_p right, vec3_p up); -void PerpendicularVector( vec3_p dst, vec3_c src ); - -float TriangleArea( vec3_c a, vec3_c b, vec3_c c ); -#endif // __cplusplus - -//============================================= - -float Com_Clamp( float min, float max, float value ); - -#define FILE_HASH_SIZE 1024 -int Com_HashString( const char *fname ); - -char *Com_SkipPath( char *pathname ); - -// it is ok for out == in -void Com_StripExtension( const char *in, char *out ); - -// "extension" should include the dot: ".map" -void Com_DefaultExtension( char *path, int maxSize, const char *extension ); - -int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ); - -/* -===================================================================================== - -SCRIPT PARSING - -===================================================================================== -*/ - -// this just controls the comment printing, it doesn't actually load a file -void Com_BeginParseSession( const char *filename ); -void Com_EndParseSession( void ); - -int Com_GetCurrentParseLine( void ); - -// Will never return NULL, just empty strings. -// An empty string will only be returned at end of file. -// ParseOnLine will return empty if there isn't another token on this line - -// this funny typedef just means a moving pointer into a const char * buffer -const char *Com_Parse( const char *(*data_p) ); -const char *Com_ParseOnLine( const char *(*data_p) ); -const char *Com_ParseRestOfLine( const char *(*data_p) ); - -void Com_UngetToken( void ); - -#ifdef __cplusplus -void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning = qfalse ); -#else -void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ); -#endif - -void Com_ScriptError( const char *msg, ... ); -void Com_ScriptWarning( const char *msg, ... ); - -void Com_SkipBracedSection( const char *(*program) ); -void Com_SkipRestOfLine( const char *(*data) ); - -float Com_ParseFloat( const char *(*buf_p) ); -int Com_ParseInt( const char *(*buf_p) ); - -void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ); -void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ); -void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ); - -//===================================================================================== -#ifdef __cplusplus - extern "C" { -#endif - -void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); - - -// mode parm for FS_FOpenFile -typedef enum { - FS_READ, - FS_WRITE, - FS_APPEND, - FS_APPEND_SYNC -} fsMode_t; - -typedef enum { - FS_SEEK_CUR, - FS_SEEK_END, - FS_SEEK_SET -} fsOrigin_t; - -//============================================= - -int Q_isprint( int c ); -int Q_islower( int c ); -int Q_isupper( int c ); -int Q_isalpha( int c ); - -// portable case insensitive compare -int Q_stricmp (const char *s1, const char *s2); -int Q_strncmp (const char *s1, const char *s2, int n); -int Q_stricmpn (const char *s1, const char *s2, int n); -char *Q_strlwr( char *s1 ); -char *Q_strupr( char *s1 ); -char *Q_strrchr( const char* string, int c ); - -// buffer size safe library replacements -void Q_strncpyz( char *dest, const char *src, int destsize ); -void Q_strcat( char *dest, int size, const char *src ); - -// strlen that discounts Quake color sequences -int Q_PrintStrlen( const char *string ); -// removes color sequences from string -char *Q_CleanStr( char *string ); - -int Com_Filter( const char *filter, const char *name, int casesensitive ); -const char *Com_StringContains( const char *str1, const char *str2, int casesensitive ); - - -//============================================= - -short BigShort(short l); -short LittleShort(short l); -int BigLong (int l); -int LittleLong (int l); -float BigFloat (float l); -float LittleFloat (float l); - -void Swap_Init (void); -char * QDECL va(char *format, ...); - -#ifdef __cplusplus - } -#endif - - -//============================================= -#ifdef __cplusplus -// -// mapfile parsing -// -typedef struct ePair_s { - char *key; - char *value; -} ePair_t; - -typedef struct mapSide_s { - char material[MAX_QPATH]; - idVec4 plane; - idVec4 textureVectors[2]; -} mapSide_t; - -typedef struct { - int numSides; - mapSide_t **sides; -} mapBrush_t; - -typedef struct { - idVec3 xyz; - float st[2]; -} patchVertex_t; - -typedef struct { - char material[MAX_QPATH]; - int width, height; - patchVertex_t *patchVerts; -} mapPatch_t; - -typedef struct { - char modelName[MAX_QPATH]; - float matrix[16]; -} mapModel_t; - -typedef struct mapPrimitive_s { - int numEpairs; - ePair_t **ePairs; - - // only one of these will be non-NULL - mapBrush_t *brush; - mapPatch_t *patch; - mapModel_t *model; -} mapPrimitive_t; - -typedef struct mapEntity_s { - int numPrimitives; - mapPrimitive_t **primitives; - - int numEpairs; - ePair_t **ePairs; -} mapEntity_t; - -typedef struct { - int numEntities; - mapEntity_t **entities; -} mapFile_t; - - -// the order of entities, brushes, and sides will be maintained, the -// lists won't be swapped on each load or save -mapFile_t *ParseMapFile( const char *text ); -void FreeMapFile( mapFile_t *mapFile ); -void WriteMapFile( const mapFile_t *mapFile, FILE *f ); - -// key names are case-insensitive -const char *ValueForMapEntityKey( const mapEntity_t *ent, const char *key ); -float FloatForMapEntityKey( const mapEntity_t *ent, const char *key ); -qboolean GetVectorForMapEntityKey( const mapEntity_t *ent, const char *key, idVec3 &vec ); - -typedef struct { - idVec3 xyz; - idVec2 st; - idVec3 normal; - idVec3 tangents[2]; - byte smoothing[4]; // colors for silhouette smoothing -} drawVert_t; - -typedef struct { - int width, height; - drawVert_t *verts; -} drawVertMesh_t; - -// Tesselate a map patch into smoothed, drawable vertexes -// MaxError of around 4 is reasonable -drawVertMesh_t *SubdivideMapPatch( const mapPatch_t *patch, float maxError ); -#endif // __cplusplus - -//========================================= - -#ifdef __cplusplus - extern "C" { -#endif - -void QDECL Com_Error( int level, const char *error, ... ); -void QDECL Com_Printf( const char *msg, ... ); -void QDECL Com_DPrintf( const char *msg, ... ); - -#ifdef __cplusplus - } -#endif - - -typedef struct { - qboolean frameMemory; - int currentElements; - int maxElements; // will reallocate and move when exceeded - void **elements; -} growList_t; - -// you don't need to init the growlist if you don't mind it growing and moving -// the list as it expands -void Com_InitGrowList( growList_t *list, int maxElements ); -int Com_AddToGrowList( growList_t *list, void *data ); -void *Com_GrowListElement( const growList_t *list, int index ); -int Com_IndexForGrowListElement( const growList_t *list, const void *element ); - - -// -// key / value info strings -// -char *Info_ValueForKey( const char *s, const char *key ); -void Info_RemoveKey( char *s, const char *key ); -void Info_SetValueForKey( char *s, const char *key, const char *value ); -qboolean Info_Validate( const char *s ); -void Info_NextPair( const char *(*s), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ); - -// get cvar defs, collision defs, etc -//#include "../shared/interface.h" - -// get key code numbers for events -//#include "../shared/keycodes.h" - -#ifdef __cplusplus -// get the polygon winding functions -//#include "../shared/windings.h" - -// get the flags class -//#include "../shared/idflags.h" -#endif // __cplusplus - -#endif // __Q_SHARED_H - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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_SHARED_H +#define __Q_SHARED_H + +// q_shared.h -- included first by ALL program modules. +// these are the definitions that have no dependance on +// central system services, and can be used by any part +// of the program without any state issues. + +// A user mod should never modify this file + +#define Q3_VERSION "DOOM 0.01" + +// alignment macros for SIMD +#define ALIGN_ON +#define ALIGN_OFF + +#ifdef _WIN32 + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4032) +#pragma warning(disable : 4051) +#pragma warning(disable : 4057) // slightly different base types +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4115) +#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence +#pragma warning(disable : 4127) // conditional expression is constant +#pragma warning(disable : 4136) +#pragma warning(disable : 4201) +#pragma warning(disable : 4214) +#pragma warning(disable : 4244) +#pragma warning(disable : 4305) // truncation from const double to float +#pragma warning(disable : 4310) // cast truncates constant value +#pragma warning(disable : 4514) +#pragma warning(disable : 4711) // selected for automatic inline expansion +#pragma warning(disable : 4220) // varargs matches remaining parameters + +#endif + +#include <assert.h> +#include <math.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdlib.h> +#include <time.h> +#include <ctype.h> +#ifdef _WIN32 // mac doesn't have malloc.h +#include <malloc.h> // for _alloca() +#endif +#ifdef _WIN32 + +//#pragma intrinsic( memset, memcpy ) + +#endif + + +// this is the define for determining if we have an asm version of a C function +#if (defined _M_IX86 || defined __i386__) && !defined __sun__ && !defined __LCC__ +#define id386 1 +#else +#define id386 0 +#endif + +// for windows fastcall option + +#define QDECL + +//======================= WIN32 DEFINES ================================= + +#ifdef _WIN32 + +#define MAC_STATIC + +#undef QDECL +#define QDECL __cdecl + +// buildstring will be incorporated into the version string +#ifdef NDEBUG +#ifdef _M_IX86 +#define CPUSTRING "win-x86" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP" +#endif +#else +#ifdef _M_IX86 +#define CPUSTRING "win-x86-debug" +#elif defined _M_ALPHA +#define CPUSTRING "win-AXP-debug" +#endif +#endif + + +#define PATH_SEP '\\' + +#endif + +//======================= MAC OS X SERVER DEFINES ===================== + +#if defined(__MACH__) && defined(__APPLE__) + +#define MAC_STATIC + +#ifdef __ppc__ +#define CPUSTRING "MacOSXS-ppc" +#elif defined __i386__ +#define CPUSTRING "MacOSXS-i386" +#else +#define CPUSTRING "MacOSXS-other" +#endif + +#define PATH_SEP '/' + +#define GAME_HARD_LINKED +#define CGAME_HARD_LINKED +#define UI_HARD_LINKED +#define _alloca alloca + +#undef ALIGN_ON +#undef ALIGN_OFF +#define ALIGN_ON #pragma align(16) +#define ALIGN_OFF #pragma align() + +#ifdef __cplusplus + extern "C" { +#endif + +void *osxAllocateMemory(long size); +void osxFreeMemory(void *pointer); + +#ifdef __cplusplus + } +#endif + +#endif + +//======================= MAC DEFINES ================================= + +#ifdef __MACOS__ + +#define MAC_STATIC static + +#define CPUSTRING "MacOS-PPC" + +#define PATH_SEP ':' + +void Sys_PumpEvents( void ); + +#endif + +#ifdef __MRC__ + +#define MAC_STATIC + +#define CPUSTRING "MacOS-PPC" + +#define PATH_SEP ':' + +void Sys_PumpEvents( void ); + +#undef QDECL +#define QDECL __cdecl + +#define _alloca alloca +#endif + +//======================= LINUX DEFINES ================================= + +// the mac compiler can't handle >32k of locals, so we +// just waste space and make big arrays static... +#ifdef __linux__ + +#define MAC_STATIC + +#ifdef __i386__ +#define CPUSTRING "linux-i386" +#elif defined __axp__ +#define CPUSTRING "linux-alpha" +#else +#define CPUSTRING "linux-other" +#endif + +#define PATH_SEP '/' + +#endif + +//============================================================= + +typedef enum {qfalse, qtrue} qboolean; + +typedef unsigned char byte; + +#define EQUAL_EPSILON 0.001 + +typedef int qhandle_t; +typedef int sfxHandle_t; +typedef int fileHandle_t; +typedef int clipHandle_t; + +typedef enum { + INVALID_JOINT = -1 +} jointHandle_t; + +#ifndef NULL +#define NULL ((void *)0) +#endif + +#define MAX_QINT 0x7fffffff +#define MIN_QINT (-MAX_QINT-1) + +#ifndef max +#define max( x, y ) ( ( ( x ) > ( y ) ) ? ( x ) : ( y ) ) +#define min( x, y ) ( ( ( x ) < ( y ) ) ? ( x ) : ( y ) ) +#endif + +#ifndef sign +#define sign( f ) ( ( f > 0 ) ? 1 : ( ( f < 0 ) ? -1 : 0 ) ) +#endif + +// angle indexes +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over + +// the game guarantees that no string from the network will ever +// exceed MAX_STRING_CHARS +#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString +#define MAX_STRING_TOKENS 256 // max tokens resulting from Cmd_TokenizeString +#define MAX_TOKEN_CHARS 1024 // max length of an individual token + +#define MAX_INFO_STRING 1024 +#define MAX_INFO_KEY 1024 +#define MAX_INFO_VALUE 1024 + + +#define MAX_QPATH 64 // max length of a quake game pathname +#define MAX_OSPATH 128 // max length of a filesystem pathname + +#define MAX_NAME_LENGTH 32 // max length of a client name + +// paramters for command buffer stuffing +typedef enum { + EXEC_NOW, // don't return until completed, a VM should NEVER use this, + // because some commands might cause the VM to be unloaded... + EXEC_INSERT, // insert at current position, but don't run yet + EXEC_APPEND // add to end of the command buffer (normal case) +} cbufExec_t; + + +// +// these aren't needed by any of the VMs. put in another header? +// +#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility + +#undef ERR_FATAL // malloc.h on unix + +// parameters to the main Error routine +typedef enum { + ERR_NONE, + ERR_FATAL, // exit the entire game with a popup window + ERR_DROP, // print to console and disconnect from game + ERR_DISCONNECT, // don't kill server + ERR_NEED_CD // pop up the need-cd dialog +} errorParm_t; + + +// font rendering values used by ui and cgame + +#define PROP_GAP_WIDTH 3 +#define PROP_SPACE_WIDTH 8 +#define PROP_HEIGHT 27 +#define PROP_SMALL_SIZE_SCALE 0.75 + +#define BLINK_DIVISOR 200 +#define PULSE_DIVISOR 75 + +#define UI_LEFT 0x00000000 // default +#define UI_CENTER 0x00000001 +#define UI_RIGHT 0x00000002 +#define UI_FORMATMASK 0x00000007 +#define UI_SMALLFONT 0x00000010 +#define UI_BIGFONT 0x00000020 // default +#define UI_GIANTFONT 0x00000040 +#define UI_DROPSHADOW 0x00000800 +#define UI_BLINK 0x00001000 +#define UI_INVERSE 0x00002000 +#define UI_PULSE 0x00004000 + + +/* +============================================================== + +MATHLIB + +============================================================== +*/ +#ifdef __cplusplus // so we can include this in C code +#define SIDE_FRONT 0 +#define SIDE_BACK 1 +#define SIDE_ON 2 +#define SIDE_CROSS 3 + +#define Q_PI 3.14159265358979323846 +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#include "math_vector.h" +#include "math_angles.h" +#include "math_matrix.h" +#include "math_quaternion.h" + +class idVec3; // for defining vectors +typedef idVec3 &vec3_p; // for passing vectors as function arguments +typedef const idVec3 &vec3_c; // for passing vectors as const function arguments + +class angles_t; // for defining angle vectors +typedef angles_t &angles_p; // for passing angles as function arguments +typedef const angles_t &angles_c; // for passing angles as const function arguments + +class mat3_t; // for defining matrices +typedef mat3_t &mat3_p; // for passing matrices as function arguments +typedef const mat3_t &mat3_c; // for passing matrices as const function arguments + + + +#define NUMVERTEXNORMALS 162 +extern idVec3 bytedirs[NUMVERTEXNORMALS]; + +// all drawing is done to a 640*480 virtual screen size +// and will be automatically scaled to the real resolution +#define SCREEN_WIDTH 640 +#define SCREEN_HEIGHT 480 + +#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH) +#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2) + +#define SMALLCHAR_WIDTH 8 +#define SMALLCHAR_HEIGHT 16 + +#define BIGCHAR_WIDTH 16 +#define BIGCHAR_HEIGHT 16 + +#define GIANTCHAR_WIDTH 32 +#define GIANTCHAR_HEIGHT 48 + +extern idVec4 colorBlack; +extern idVec4 colorRed; +extern idVec4 colorGreen; +extern idVec4 colorBlue; +extern idVec4 colorYellow; +extern idVec4 colorMagenta; +extern idVec4 colorCyan; +extern idVec4 colorWhite; +extern idVec4 colorLtGrey; +extern idVec4 colorMdGrey; +extern idVec4 colorDkGrey; + +#define Q_COLOR_ESCAPE '^' +#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE ) + +#define COLOR_BLACK '0' +#define COLOR_RED '1' +#define COLOR_GREEN '2' +#define COLOR_YELLOW '3' +#define COLOR_BLUE '4' +#define COLOR_CYAN '5' +#define COLOR_MAGENTA '6' +#define COLOR_WHITE '7' +#define ColorIndex(c) ( ( (c) - '0' ) & 7 ) + +#define S_COLOR_BLACK "^0" +#define S_COLOR_RED "^1" +#define S_COLOR_GREEN "^2" +#define S_COLOR_YELLOW "^3" +#define S_COLOR_BLUE "^4" +#define S_COLOR_CYAN "^5" +#define S_COLOR_MAGENTA "^6" +#define S_COLOR_WHITE "^7" + +extern idVec4 g_color_table[8]; + +#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b +#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a + +#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F ) +#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI ) + +struct cplane_s; + +extern idVec3 vec3_origin; +extern idVec4 vec4_origin; +extern mat3_t axisDefault; + +#define nanmask (255<<23) + +#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) + +float Q_fabs( float f ); +float Q_rsqrt( float f ); // reciprocal square root + +#define SQRTFAST( x ) ( 1.0f / Q_rsqrt( x ) ) + +signed char ClampChar( int i ); +signed short ClampShort( int i ); + +// this isn't a real cheap function to call! +int DirToByte( const idVec3 &dir ); +void ByteToDir( int b, vec3_p dir ); + +#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 VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z]) + +#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];} + +float NormalizeColor( vec3_c in, vec3_p out ); + +int VectorCompare( vec3_c v1, vec3_c v2 ); +float VectorLength( vec3_c v ); +float Distance( vec3_c p1, vec3_c p2 ); +float DistanceSquared( vec3_c p1, vec3_c p2 ); +float VectorNormalize (vec3_p v); // returns vector length +void VectorNormalizeFast(vec3_p v); // does NOT return vector length, uses rsqrt approximation +float VectorNormalize2( vec3_c v, vec3_p out ); +void VectorInverse (vec3_p v); +void VectorRotate( vec3_c in, mat3_c matrix, vec3_p out ); +void VectorPolar(vec3_p v, float radius, float theta, float phi); +void VectorSnap(vec3_p v); +void Vector53Copy( const idVec5_t &in, vec3_p out); +void Vector5Scale( const idVec5_t &v, float scale, idVec5_t &out); +void Vector5Add( const idVec5_t &va, const idVec5_t &vb, idVec5_t &out); +void VectorRotate3( vec3_c vIn, vec3_c vRotation, vec3_p out); +void VectorRotate3Origin(vec3_c vIn, vec3_c vRotation, vec3_c vOrigin, vec3_p out); + + +int Q_log2(int val); + +int Q_rand( int *seed ); +float Q_random( int *seed ); +float Q_crandom( int *seed ); + +#define random() ((rand () & 0x7fff) / ((float)0x7fff)) +#define crandom() (2.0 * (random() - 0.5)) + +float Q_rint( float in ); + +void vectoangles( vec3_c value1, angles_p angles); +void AnglesToAxis( angles_c angles, mat3_p axis ); + +void AxisCopy( mat3_c in, mat3_p out ); +qboolean AxisRotated( mat3_c in ); // assumes a non-degenerate axis + +int SignbitsForNormal( vec3_c normal ); +int BoxOnPlaneSide( const Bounds &b, struct cplane_s *p ); + +float AngleMod(float a); +float LerpAngle (float from, float to, float frac); +float AngleSubtract( float a1, float a2 ); +void AnglesSubtract( angles_c v1, angles_c v2, angles_p v3 ); + +float AngleNormalize360 ( float angle ); +float AngleNormalize180 ( float angle ); +float AngleDelta ( float angle1, float angle2 ); + +qboolean PlaneFromPoints( idVec4 &plane, vec3_c a, vec3_c b, vec3_c c ); +void ProjectPointOnPlane( vec3_p dst, vec3_c p, vec3_c normal ); +void RotatePointAroundVector( vec3_p dst, vec3_c dir, vec3_c point, float degrees ); +void RotateAroundDirection( mat3_p axis, float yaw ); +void MakeNormalVectors( vec3_c forward, vec3_p right, vec3_p up ); +// perpendicular vector could be replaced by this + +int PlaneTypeForNormal( vec3_c normal ); + +void MatrixMultiply( mat3_c in1, mat3_c in2, mat3_p out ); +void MatrixInverseMultiply( mat3_c in1, mat3_c in2, mat3_p out ); // in2 is transposed during multiply +void MatrixTransformVector( vec3_c in, mat3_c matrix, vec3_p out ); +void MatrixProjectVector( vec3_c in, mat3_c matrix, vec3_p out ); // Places the vector into a new coordinate system. +void AngleVectors( angles_c angles, vec3_p forward, vec3_p right, vec3_p up); +void PerpendicularVector( vec3_p dst, vec3_c src ); + +float TriangleArea( vec3_c a, vec3_c b, vec3_c c ); +#endif // __cplusplus + +//============================================= + +float Com_Clamp( float min, float max, float value ); + +#define FILE_HASH_SIZE 1024 +int Com_HashString( const char *fname ); + +char *Com_SkipPath( char *pathname ); + +// it is ok for out == in +void Com_StripExtension( const char *in, char *out ); + +// "extension" should include the dot: ".map" +void Com_DefaultExtension( char *path, int maxSize, const char *extension ); + +int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ); + +/* +===================================================================================== + +SCRIPT PARSING + +===================================================================================== +*/ + +// this just controls the comment printing, it doesn't actually load a file +void Com_BeginParseSession( const char *filename ); +void Com_EndParseSession( void ); + +int Com_GetCurrentParseLine( void ); + +// Will never return NULL, just empty strings. +// An empty string will only be returned at end of file. +// ParseOnLine will return empty if there isn't another token on this line + +// this funny typedef just means a moving pointer into a const char * buffer +const char *Com_Parse( const char *(*data_p) ); +const char *Com_ParseOnLine( const char *(*data_p) ); +const char *Com_ParseRestOfLine( const char *(*data_p) ); + +void Com_UngetToken( void ); + +#ifdef __cplusplus +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning = qfalse ); +#else +void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ); +#endif + +void Com_ScriptError( const char *msg, ... ); +void Com_ScriptWarning( const char *msg, ... ); + +void Com_SkipBracedSection( const char *(*program) ); +void Com_SkipRestOfLine( const char *(*data) ); + +float Com_ParseFloat( const char *(*buf_p) ); +int Com_ParseInt( const char *(*buf_p) ); + +void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ); +void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ); +void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ); + +//===================================================================================== +#ifdef __cplusplus + extern "C" { +#endif + +void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...); + + +// mode parm for FS_FOpenFile +typedef enum { + FS_READ, + FS_WRITE, + FS_APPEND, + FS_APPEND_SYNC +} fsMode_t; + +typedef enum { + FS_SEEK_CUR, + FS_SEEK_END, + FS_SEEK_SET +} fsOrigin_t; + +//============================================= + +int Q_isprint( int c ); +int Q_islower( int c ); +int Q_isupper( int c ); +int Q_isalpha( int c ); + +// portable case insensitive compare +int Q_stricmp (const char *s1, const char *s2); +int Q_strncmp (const char *s1, const char *s2, int n); +int Q_stricmpn (const char *s1, const char *s2, int n); +char *Q_strlwr( char *s1 ); +char *Q_strupr( char *s1 ); +char *Q_strrchr( const char* string, int c ); + +// buffer size safe library replacements +void Q_strncpyz( char *dest, const char *src, int destsize ); +void Q_strcat( char *dest, int size, const char *src ); + +// strlen that discounts Quake color sequences +int Q_PrintStrlen( const char *string ); +// removes color sequences from string +char *Q_CleanStr( char *string ); + +int Com_Filter( const char *filter, const char *name, int casesensitive ); +const char *Com_StringContains( const char *str1, const char *str2, int casesensitive ); + + +//============================================= + +short BigShort(short l); +short LittleShort(short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + +void Swap_Init (void); +char * QDECL va(char *format, ...); + +#ifdef __cplusplus + } +#endif + + +//============================================= +#ifdef __cplusplus +// +// mapfile parsing +// +typedef struct ePair_s { + char *key; + char *value; +} ePair_t; + +typedef struct mapSide_s { + char material[MAX_QPATH]; + idVec4 plane; + idVec4 textureVectors[2]; +} mapSide_t; + +typedef struct { + int numSides; + mapSide_t **sides; +} mapBrush_t; + +typedef struct { + idVec3 xyz; + float st[2]; +} patchVertex_t; + +typedef struct { + char material[MAX_QPATH]; + int width, height; + patchVertex_t *patchVerts; +} mapPatch_t; + +typedef struct { + char modelName[MAX_QPATH]; + float matrix[16]; +} mapModel_t; + +typedef struct mapPrimitive_s { + int numEpairs; + ePair_t **ePairs; + + // only one of these will be non-NULL + mapBrush_t *brush; + mapPatch_t *patch; + mapModel_t *model; +} mapPrimitive_t; + +typedef struct mapEntity_s { + int numPrimitives; + mapPrimitive_t **primitives; + + int numEpairs; + ePair_t **ePairs; +} mapEntity_t; + +typedef struct { + int numEntities; + mapEntity_t **entities; +} mapFile_t; + + +// the order of entities, brushes, and sides will be maintained, the +// lists won't be swapped on each load or save +mapFile_t *ParseMapFile( const char *text ); +void FreeMapFile( mapFile_t *mapFile ); +void WriteMapFile( const mapFile_t *mapFile, FILE *f ); + +// key names are case-insensitive +const char *ValueForMapEntityKey( const mapEntity_t *ent, const char *key ); +float FloatForMapEntityKey( const mapEntity_t *ent, const char *key ); +qboolean GetVectorForMapEntityKey( const mapEntity_t *ent, const char *key, idVec3 &vec ); + +typedef struct { + idVec3 xyz; + idVec2 st; + idVec3 normal; + idVec3 tangents[2]; + byte smoothing[4]; // colors for silhouette smoothing +} drawVert_t; + +typedef struct { + int width, height; + drawVert_t *verts; +} drawVertMesh_t; + +// Tesselate a map patch into smoothed, drawable vertexes +// MaxError of around 4 is reasonable +drawVertMesh_t *SubdivideMapPatch( const mapPatch_t *patch, float maxError ); +#endif // __cplusplus + +//========================================= + +#ifdef __cplusplus + extern "C" { +#endif + +void QDECL Com_Error( int level, const char *error, ... ); +void QDECL Com_Printf( const char *msg, ... ); +void QDECL Com_DPrintf( const char *msg, ... ); + +#ifdef __cplusplus + } +#endif + + +typedef struct { + qboolean frameMemory; + int currentElements; + int maxElements; // will reallocate and move when exceeded + void **elements; +} growList_t; + +// you don't need to init the growlist if you don't mind it growing and moving +// the list as it expands +void Com_InitGrowList( growList_t *list, int maxElements ); +int Com_AddToGrowList( growList_t *list, void *data ); +void *Com_GrowListElement( const growList_t *list, int index ); +int Com_IndexForGrowListElement( const growList_t *list, const void *element ); + + +// +// key / value info strings +// +char *Info_ValueForKey( const char *s, const char *key ); +void Info_RemoveKey( char *s, const char *key ); +void Info_SetValueForKey( char *s, const char *key, const char *value ); +qboolean Info_Validate( const char *s ); +void Info_NextPair( const char *(*s), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ); + +// get cvar defs, collision defs, etc +//#include "../shared/interface.h" + +// get key code numbers for events +//#include "../shared/keycodes.h" + +#ifdef __cplusplus +// get the polygon winding functions +//#include "../shared/windings.h" + +// get the flags class +//#include "../shared/idflags.h" +#endif // __cplusplus + +#endif // __Q_SHARED_H + diff --git a/libs/splines/splines.h b/libs/splines/splines.h index da7c2e5b..54808492 100644 --- a/libs/splines/splines.h +++ b/libs/splines/splines.h @@ -1,1102 +1,1102 @@ -#ifndef __SPLINES_H -#define __SPLINES_H - -#define GTKRADIANT - -#ifndef CAMERA_PLUGIN -#ifdef GTKRADIANT -#include "misc_def.h" -#include "igl_to_qgl.h" -#endif -#endif - -#include "util_list.h" -#include "util_str.h" -#include "math_vector.h" - -typedef int fileHandle_t; - -extern void glBox(idVec3 &color, idVec3 &point, float size); -extern void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label); - -static idVec4 blue(0, 0, 1, 1); -static idVec4 red(1, 0, 0, 1); - -class idPointListInterface { -public: - idPointListInterface() { - selectedPoints.Clear(); - }; - virtual ~idPointListInterface() {}; - - virtual int numPoints() { - return 0; - } - - virtual void addPoint(const float x, const float y, const float z) {} - virtual void addPoint(const idVec3 &v) {} - virtual void removePoint(int index) {} - virtual idVec3 *getPoint(int index) { return NULL; } - - int selectPointByRay(float ox, float oy, float oz, float dx, float dy, float dz, bool single) { - idVec3 origin(ox, oy, oz); - idVec3 dir(dx, dy, dz); - return selectPointByRay(origin, dir, single); - } - - int selectPointByRay(const idVec3 origin, const idVec3 direction, bool single) { - int i, besti, count; - float d, bestd; - idVec3 temp, temp2; - - // find the point closest to the ray - besti = -1; - bestd = 8; - count = numPoints(); - - for (i=0; i < count; i++) { - temp = *getPoint(i); - temp2 = temp; - temp -= origin; - d = DotProduct(temp, direction); - __VectorMA (origin, d, direction, temp); - temp2 -= temp; - d = temp2.Length(); - if (d <= bestd) { - bestd = d; - besti = i; - } - } - - if (besti >= 0) { - selectPoint(besti, single); - } - - return besti; - } - - int isPointSelected(int index) { - int count = selectedPoints.Num(); - for (int i = 0; i < count; i++) { - if (selectedPoints[i] == index) { - return i; - } - } - return -1; - } - - int selectPoint(int index, bool single) { - if (index >= 0 && index < numPoints()) { - if (single) { - deselectAll(); - } else { - if (isPointSelected(index) >= 0) { - selectedPoints.Remove(index); - } - } - return selectedPoints.Append(index); - } - return -1; - } - - void selectAll() { - selectedPoints.Clear(); - for (int i = 0; i < numPoints(); i++) { - selectedPoints.Append(i); - } - } - - void deselectAll() { - selectedPoints.Clear(); - } - - int numSelectedPoints(); - - idVec3 *getSelectedPoint(int index) { - assert(index >= 0 && index < numSelectedPoints()); - return getPoint(selectedPoints[index]); - } - - virtual void updateSelection(float x, float y, float z) { - idVec3 move(x, y, z); - updateSelection(move); - } - - virtual void updateSelection(const idVec3 &move) { - int count = selectedPoints.Num(); - for (int i = 0; i < count; i++) { - *getPoint(selectedPoints[i]) += move; - } - } - - void drawSelection() { - int count = selectedPoints.Num(); - for (int i = 0; i < count; i++) { - glBox(red, *getPoint(selectedPoints[i]), 4); - } - } - -protected: - idList<int> selectedPoints; - -}; - - -class idSplineList { - -public: - - idSplineList() { - clear(); - } - - idSplineList(const char *p) { - clear(); - name = p; - }; - - ~idSplineList() { - clear(); - }; - - void clearControl() { - for (int i = 0; i < controlPoints.Num(); i++) { - delete controlPoints[i]; - } - controlPoints.Clear(); - } - - void clearSpline() { - for (int i = 0; i < splinePoints.Num(); i++) { - delete splinePoints[i]; - } - splinePoints.Clear(); - } - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - - void clear() { - clearControl(); - clearSpline(); - splineTime.Clear(); - selected = NULL; - dirty = true; - activeSegment = 0; - granularity = 0.025f; - pathColor.set(1.0f, 0.5f, 0.0f); - controlColor.set(0.7f, 0.0f, 1.0f); - segmentColor.set(0.0f, 0.0f, 1.0f); - activeColor.set(1.0f, 0.0f, 0.0f); - } - - void initPosition(long startTime, long totalTime); - const idVec3 *getPosition(long time); - - - void draw(bool editMode); - void addToRenderer(); - - void setSelectedPoint(idVec3 *p); - idVec3 *getSelectedPoint() { - return selected; - } - - void addPoint(const idVec3 &v) { - controlPoints.Append(new idVec3(v)); - dirty = true; - } - - void addPoint(float x, float y, float z) { - controlPoints.Append(new idVec3(x, y, z)); - dirty = true; - } - - void updateSelection(const idVec3 &move); - - void startEdit() { - editMode = true; - } - - void stopEdit() { - editMode = false; - } - - void buildSpline(); - - void setGranularity(float f) { - granularity = f; - } - - float getGranularity() { - return granularity; - } - - int numPoints() { - return controlPoints.Num(); - } - - idVec3 *getPoint(int index) { - assert(index >= 0 && index < controlPoints.Num()); - return controlPoints[index]; - } - - idVec3 *getSegmentPoint(int index) { - assert(index >= 0 && index < splinePoints.Num()); - return splinePoints[index]; - } - - - void setSegmentTime(int index, int time) { - assert(index >= 0 && index < splinePoints.Num()); - splineTime[index] = time; - } - - int getSegmentTime(int index) { - assert(index >= 0 && index < splinePoints.Num()); - return (int)splineTime[index]; - } - void addSegmentTime(int index, int time) { - assert(index >= 0 && index < splinePoints.Num()); - splineTime[index] += time; - } - - float totalDistance(); - - static idVec3 zero; - - int getActiveSegment() { - return activeSegment; - } - - void setActiveSegment(int i) { - //assert(i >= 0 && (splinePoints.Num() > 0 && i < splinePoints.Num())); - activeSegment = i; - } - - int numSegments() { - return splinePoints.Num(); - } - - void setColors(idVec3 &path, idVec3 &segment, idVec3 &control, idVec3 &active) { - pathColor = path; - segmentColor = segment; - controlColor = control; - activeColor = active; - } - - const char *getName() { - return name.c_str(); - } - - void setName(const char *p) { - name = p; - } - - bool validTime() { - if (dirty) { - buildSpline(); - } - // gcc doesn't allow static casting away from bools - // why? I've no idea... - return (bool)(splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num()); - } - - void setTime(long t) { - time = t; - } - - void setBaseTime(long t) { - baseTime = t; - } - -protected: - idStr name; - float calcSpline(int step, float tension); - idList<idVec3*> controlPoints; - idList<idVec3*> splinePoints; - idList<double> splineTime; - idVec3 *selected; - idVec3 pathColor, segmentColor, controlColor, activeColor; - float granularity; - bool editMode; - bool dirty; - int activeSegment; - long baseTime; - long time; - friend class idCamera; -}; - -// time in milliseconds -// velocity where 1.0 equal rough walking speed -struct idVelocity { - idVelocity(long start, long duration, float s) { - startTime = start; - time = duration; - speed = s; - } - long startTime; - long time; - float speed; -}; - -// can either be a look at or origin position for a camera -// -class idCameraPosition : public idPointListInterface { -public: - - virtual void clearVelocities() { - for (int i = 0; i < velocities.Num(); i++) { - delete velocities[i]; - velocities[i] = NULL; - } - velocities.Clear(); - } - - virtual void clear() { - editMode = false; - clearVelocities(); - } - - idCameraPosition(const char *p) { - name = p; - } - - idCameraPosition() { - time = 0; - name = "position"; - } - - idCameraPosition(long t) { - time = t; - } - - virtual ~idCameraPosition() { - clear(); - } - - - // this can be done with RTTI syntax but i like the derived classes setting a type - // makes serialization a bit easier to see - // - enum positionType { - FIXED = 0x00, - INTERPOLATED, - SPLINE, - POSITION_COUNT - }; - - - virtual void start(long t) { - startTime = t; - } - - long getTime() { - return time; - } - - virtual void setTime(long t) { - time = t; - } - - float getBaseVelocity() { - return baseVelocity; - } - - float getVelocity(long t) { - long check = t - startTime; - for (int i = 0; i < velocities.Num(); i++) { - if (check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time) { - return velocities[i]->speed; - } - } - return baseVelocity; - } - - void addVelocity(long start, long duration, float speed) { - velocities.Append(new idVelocity(start, duration, speed)); - } - - virtual const idVec3 *getPosition(long t) { - assert(true); - return NULL; - } - - virtual void draw(bool editMode) {}; - - virtual void parse(const char *(*text)) {}; - virtual void write(fileHandle_t file, const char *name); - virtual bool parseToken(const char *key, const char *(*text)); - - const char *getName() { - return name.c_str(); - } - - void setName(const char *p) { - name = p; - } - - virtual void startEdit() { - editMode = true; - } - - virtual void stopEdit() { - editMode = false; - } - - virtual void draw() {}; - - const char *typeStr() { - return positionStr[static_cast<int>(type)]; - } - - void calcVelocity(float distance) { - float secs = (float)time / 1000; - baseVelocity = distance / secs; - } - -protected: - static const char* positionStr[POSITION_COUNT]; - long startTime; - long time; - idCameraPosition::positionType type; - idStr name; - bool editMode; - idList<idVelocity*> velocities; - float baseVelocity; -}; - -class idFixedPosition : public idCameraPosition { -public: - - void init() { - pos.Zero(); - type = idCameraPosition::FIXED; - } - - idFixedPosition() : idCameraPosition() { - init(); - } - - idFixedPosition(idVec3 p) : idCameraPosition() { - init(); - pos = p; - } - - virtual void addPoint(const idVec3 &v) { - pos = v; - } - - virtual void addPoint(const float x, const float y, const float z) { - pos.set(x, y, z); - } - - - ~idFixedPosition() { - } - - virtual const idVec3 *getPosition(long t) { - return &pos; - } - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - - virtual int numPoints() { - return 1; - } - - virtual idVec3 *getPoint(int index) { - if (index != 0) { - assert(true); - }; - return &pos; - } - - virtual void draw(bool editMode) { - glLabeledPoint(blue, pos, (editMode) ? 5 : 3, "Fixed point"); - } - -protected: - idVec3 pos; -}; - -class idInterpolatedPosition : public idCameraPosition { -public: - - void init() { - type = idCameraPosition::INTERPOLATED; - first = true; - startPos.Zero(); - endPos.Zero(); - } - - idInterpolatedPosition() : idCameraPosition() { - init(); - } - - idInterpolatedPosition(idVec3 start, idVec3 end, long time) : idCameraPosition(time) { - init(); - startPos = start; - endPos = end; - } - - ~idInterpolatedPosition() { - } - - virtual const idVec3 *getPosition(long t); - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - - virtual int numPoints() { - return 2; - } - - virtual idVec3 *getPoint(int index) { - assert(index >= 0 && index < 2); - if (index == 0) { - return &startPos; - } - return &endPos; - } - - virtual void addPoint(const float x, const float y, const float z) { - if (first) { - startPos.set(x, y, z); - first = false; - } else { - endPos.set(x, y, z); - first = true; - } - } - - virtual void addPoint(const idVec3 &v) { - if (first) { - startPos = v; - first = false; - } else { - endPos = v; - first = true; - } - } - - virtual void draw(bool editMode) { - glLabeledPoint(blue, startPos, (editMode) ? 5 : 3, "Start interpolated"); - glLabeledPoint(blue, endPos, (editMode) ? 5 : 3, "End interpolated"); - qglBegin(GL_LINES); - qglVertex3fv(startPos); - qglVertex3fv(endPos); - qglEnd(); - } - - virtual void start(long t) { - idCameraPosition::start(t); - lastTime = startTime; - distSoFar = 0.0; - idVec3 temp = startPos; - temp -= endPos; - calcVelocity(temp.Length()); - } - -protected: - bool first; - idVec3 startPos; - idVec3 endPos; - long lastTime; - float distSoFar; -}; - -class idSplinePosition : public idCameraPosition { -public: - - void init() { - type = idCameraPosition::SPLINE; - } - - idSplinePosition() : idCameraPosition() { - init(); - } - - idSplinePosition(long time) : idCameraPosition(time) { - init(); - } - - ~idSplinePosition() { - } - - virtual void start(long t) { - idCameraPosition::start(t); - target.initPosition(t, time); - lastTime = startTime; - distSoFar = 0.0; - calcVelocity(target.totalDistance()); - } - - //virtual const idVec3 *getPosition(long t) { - // return target.getPosition(t); - //} - virtual const idVec3 *getPosition(long t); - - - //virtual const idVec3 *getPosition(long t) const { - - void addControlPoint(idVec3 &v) { - target.addPoint(v); - } - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - - virtual int numPoints() { - return target.numPoints(); - } - - virtual idVec3 *getPoint(int index) { - return target.getPoint(index); - } - - virtual void addPoint(const idVec3 &v) { - target.addPoint(v); - } - - virtual void addPoint(const float x, const float y, const float z) { - target.addPoint(x, y, z); - } - - virtual void draw(bool editMode) { - target.draw(editMode); - } - - virtual void updateSelection(const idVec3 &move) { - idCameraPosition::updateSelection(move); - target.buildSpline(); - } - -protected: - idSplineList target; - long lastTime; - float distSoFar; -}; - -class idCameraFOV { -public: - - idCameraFOV() { - time = 0; - length = 0; - fov = 90; - } - - idCameraFOV(int v) { - time = 0; - length = 0; - fov = v; - } - - idCameraFOV(int s, int e, long t) { - startFOV = s; - endFOV = e; - length = t; - } - - - ~idCameraFOV(){} - - void setFOV(float f) { - fov = f; - } - - float getFOV(long t) { - if (length) { - float percent = (t - startTime) / length; - if (percent < 0.0) { - percent = 0.0; - } else if (percent > 1.0) { - percent = 1.0; - } - float temp = endFOV - startFOV; - temp *= percent; - fov = startFOV + temp; - - if (percent == 1.0) { - length = 0.0; - } - } - return fov; - } - - void start(long t) { - startTime = t; - } - - void reset(float startfov, float endfov, int start, float len) { - startFOV = startfov; - endFOV = endfov; - startTime = start; - length = len * 1000; - } - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - -protected: - float fov; - float startFOV; - float endFOV; - int startTime; - int time; - float length; -}; - - - - -class idCameraEvent { -public: // parameters - enum eventType { - 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 - }; - - static const char* eventStr[EVENT_COUNT]; - - idCameraEvent() { - paramStr = ""; - type = EVENT_NA; - time = 0; - } - - idCameraEvent(eventType t, const char *param, long n) { - type = t; - paramStr = param; - time = n; - } - - ~idCameraEvent() {}; - - eventType getType() { - return type; - } - - const char *typeStr() { - return eventStr[static_cast<int>(type)]; - } - - const char *getParam() { - return paramStr.c_str(); - } - - long getTime() { - return time; - } - - void setTime(long n) { - time = n; - } - - void parse(const char *(*text)); - void write(fileHandle_t file, const char *name); - - void setTriggered(bool b) { - triggered = b; - } - - bool getTriggered() { - return triggered; - } - -protected: - eventType type; - idStr paramStr; - long time; - bool triggered; - -}; - -class idCameraDef { -public: - - void clear() { - currentCameraPosition = 0; - cameraRunning = false; - lastDirection.Zero(); - baseTime = 30; - activeTarget = 0; - name = "camera01"; - fov.setFOV(90); - int i; - for (i = 0; i < targetPositions.Num(); i++) { - delete targetPositions[i]; - } - for (i = 0; i < events.Num(); i++) { - delete events[i]; - } - delete cameraPosition; - cameraPosition = NULL; - events.Clear(); - targetPositions.Clear(); - } - - idCameraPosition *startNewCamera(idCameraPosition::positionType type) { - clear(); - if (type == idCameraPosition::SPLINE) { - cameraPosition = new idSplinePosition(); - } else if (type == idCameraPosition::INTERPOLATED) { - cameraPosition = new idInterpolatedPosition(); - } else { - cameraPosition = new idFixedPosition(); - } - return cameraPosition; - } - - idCameraDef() { - cameraPosition = NULL; - clear(); - } - - ~idCameraDef() { - clear(); - } - - void addEvent(idCameraEvent::eventType t, const char *param, long time); - - void addEvent(idCameraEvent *event); - - void removeEvent( int index); - - static int sortEvents(const void *p1, const void *p2); - - int numEvents() { - return events.Num(); - } - - idCameraEvent *getEvent(int index) { - assert(index >= 0 && index < events.Num()); - return events[index]; - } - - void parse(const char *(*text)); - bool load(const char *filename); - void save(const char *filename); - - void buildCamera(); - - //idSplineList *getcameraPosition() { - // return &cameraPosition; - //} - - static idCameraPosition *newFromType(idCameraPosition::positionType t) { - switch (t) { - case idCameraPosition::FIXED : return new idFixedPosition(); - case idCameraPosition::INTERPOLATED : return new idInterpolatedPosition(); - case idCameraPosition::SPLINE : return new idSplinePosition(); - default: - break; - }; - return NULL; - } - - void addTarget(const char *name, idCameraPosition::positionType type); - - idCameraPosition *getActiveTarget() { - if (targetPositions.Num() == 0) { - addTarget(NULL, idCameraPosition::FIXED); - } - return targetPositions[activeTarget]; - } - - idCameraPosition *getActiveTarget(int index) { - if (targetPositions.Num() == 0) { - addTarget(NULL, idCameraPosition::FIXED); - return targetPositions[0]; - } - return targetPositions[index]; - } - - int numTargets() { - return targetPositions.Num(); - } - - - void setActiveTargetByName(const char *name) { - for (int i = 0; i < targetPositions.Num(); i++) { - if (Q_stricmp(name, targetPositions[i]->getName()) == 0) { - setActiveTarget(i); - return; - } - } - } - - void setActiveTarget(int index) { - assert(index >= 0 && index < targetPositions.Num()); - activeTarget = index; - } - - void setRunning(bool b) { - cameraRunning = b; - } - - void setBaseTime(float f) { - baseTime = f; - } - - float getBaseTime() { - return baseTime; - } - - float getTotalTime() { - return totalTime; - } - - void startCamera(long t); - void stopCamera() { - cameraRunning = true; - } - void getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fv); - - bool getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv); - bool getCameraInfo(long time, float *origin, float *direction, float *fv) { - idVec3 org, dir; - org[0] = origin[0]; - org[1] = origin[1]; - org[2] = origin[2]; - dir[0] = direction[0]; - dir[1] = direction[1]; - dir[2] = direction[2]; - bool b = getCameraInfo(time, org, dir, fv); - origin[0] = org[0]; - origin[1] = org[1]; - origin[2] = org[2]; - direction[0] = dir[0]; - direction[1] = dir[1]; - direction[2] = dir[2]; - return b; - } - - void draw(bool editMode) { - // gcc doesn't allow casting away from bools - // why? I've no idea... - if (cameraPosition) { - cameraPosition->draw((bool)((editMode || cameraRunning) && cameraEdit)); - int count = targetPositions.Num(); - for (int i = 0; i < count; i++) { - targetPositions[i]->draw((bool)((editMode || cameraRunning) && i == activeTarget && !cameraEdit)); - } - } - } - -/* - int numSegments() { - if (cameraEdit) { - return cameraPosition.numSegments(); - } - return getTargetSpline()->numSegments(); - } - - int getActiveSegment() { - if (cameraEdit) { - return cameraPosition.getActiveSegment(); - } - return getTargetSpline()->getActiveSegment(); - } - - void setActiveSegment(int i) { - if (cameraEdit) { - cameraPosition.setActiveSegment(i); - } else { - getTargetSpline()->setActiveSegment(i); - } - } -*/ - int numPoints() { - if (cameraEdit) { - return cameraPosition->numPoints(); - } - return getActiveTarget()->numPoints(); - } - - const idVec3 *getPoint(int index) { - if (cameraEdit) { - return cameraPosition->getPoint(index); - } - return getActiveTarget()->getPoint(index); - } - - void stopEdit() { - editMode = false; - if (cameraEdit) { - cameraPosition->stopEdit(); - } else { - getActiveTarget()->stopEdit(); - } - } - - void startEdit(bool camera) { - cameraEdit = camera; - if (camera) { - cameraPosition->startEdit(); - for (int i = 0; i < targetPositions.Num(); i++) { - targetPositions[i]->stopEdit(); - } - } else { - getActiveTarget()->startEdit(); - cameraPosition->stopEdit(); - } - editMode = true; - } - - bool waitEvent(int index); - - const char *getName() { - return name.c_str(); - } - - void setName(const char *p) { - name = p; - } - - idCameraPosition *getPositionObj() { - if (cameraPosition == NULL) { - cameraPosition = new idFixedPosition(); - } - return cameraPosition; - } - -protected: - idStr name; - int currentCameraPosition; - idVec3 lastDirection; - bool cameraRunning; - idCameraPosition *cameraPosition; - idList<idCameraPosition*> targetPositions; - idList<idCameraEvent*> events; - idCameraFOV fov; - int activeTarget; - float totalTime; - float baseTime; - long startTime; - - bool cameraEdit; - bool editMode; -}; - -extern bool g_splineMode; - -extern idCameraDef *g_splineList; - - -#endif +#ifndef __SPLINES_H +#define __SPLINES_H + +#define GTKRADIANT + +#ifndef CAMERA_PLUGIN +#ifdef GTKRADIANT +#include "misc_def.h" +#include "igl_to_qgl.h" +#endif +#endif + +#include "util_list.h" +#include "util_str.h" +#include "math_vector.h" + +typedef int fileHandle_t; + +extern void glBox(idVec3 &color, idVec3 &point, float size); +extern void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label); + +static idVec4 blue(0, 0, 1, 1); +static idVec4 red(1, 0, 0, 1); + +class idPointListInterface { +public: + idPointListInterface() { + selectedPoints.Clear(); + }; + virtual ~idPointListInterface() {}; + + virtual int numPoints() { + return 0; + } + + virtual void addPoint(const float x, const float y, const float z) {} + virtual void addPoint(const idVec3 &v) {} + virtual void removePoint(int index) {} + virtual idVec3 *getPoint(int index) { return NULL; } + + int selectPointByRay(float ox, float oy, float oz, float dx, float dy, float dz, bool single) { + idVec3 origin(ox, oy, oz); + idVec3 dir(dx, dy, dz); + return selectPointByRay(origin, dir, single); + } + + int selectPointByRay(const idVec3 origin, const idVec3 direction, bool single) { + int i, besti, count; + float d, bestd; + idVec3 temp, temp2; + + // find the point closest to the ray + besti = -1; + bestd = 8; + count = numPoints(); + + for (i=0; i < count; i++) { + temp = *getPoint(i); + temp2 = temp; + temp -= origin; + d = DotProduct(temp, direction); + __VectorMA (origin, d, direction, temp); + temp2 -= temp; + d = temp2.Length(); + if (d <= bestd) { + bestd = d; + besti = i; + } + } + + if (besti >= 0) { + selectPoint(besti, single); + } + + return besti; + } + + int isPointSelected(int index) { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + if (selectedPoints[i] == index) { + return i; + } + } + return -1; + } + + int selectPoint(int index, bool single) { + if (index >= 0 && index < numPoints()) { + if (single) { + deselectAll(); + } else { + if (isPointSelected(index) >= 0) { + selectedPoints.Remove(index); + } + } + return selectedPoints.Append(index); + } + return -1; + } + + void selectAll() { + selectedPoints.Clear(); + for (int i = 0; i < numPoints(); i++) { + selectedPoints.Append(i); + } + } + + void deselectAll() { + selectedPoints.Clear(); + } + + int numSelectedPoints(); + + idVec3 *getSelectedPoint(int index) { + assert(index >= 0 && index < numSelectedPoints()); + return getPoint(selectedPoints[index]); + } + + virtual void updateSelection(float x, float y, float z) { + idVec3 move(x, y, z); + updateSelection(move); + } + + virtual void updateSelection(const idVec3 &move) { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + *getPoint(selectedPoints[i]) += move; + } + } + + void drawSelection() { + int count = selectedPoints.Num(); + for (int i = 0; i < count; i++) { + glBox(red, *getPoint(selectedPoints[i]), 4); + } + } + +protected: + idList<int> selectedPoints; + +}; + + +class idSplineList { + +public: + + idSplineList() { + clear(); + } + + idSplineList(const char *p) { + clear(); + name = p; + }; + + ~idSplineList() { + clear(); + }; + + void clearControl() { + for (int i = 0; i < controlPoints.Num(); i++) { + delete controlPoints[i]; + } + controlPoints.Clear(); + } + + void clearSpline() { + for (int i = 0; i < splinePoints.Num(); i++) { + delete splinePoints[i]; + } + splinePoints.Clear(); + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + void clear() { + clearControl(); + clearSpline(); + splineTime.Clear(); + selected = NULL; + dirty = true; + activeSegment = 0; + granularity = 0.025f; + pathColor.set(1.0f, 0.5f, 0.0f); + controlColor.set(0.7f, 0.0f, 1.0f); + segmentColor.set(0.0f, 0.0f, 1.0f); + activeColor.set(1.0f, 0.0f, 0.0f); + } + + void initPosition(long startTime, long totalTime); + const idVec3 *getPosition(long time); + + + void draw(bool editMode); + void addToRenderer(); + + void setSelectedPoint(idVec3 *p); + idVec3 *getSelectedPoint() { + return selected; + } + + void addPoint(const idVec3 &v) { + controlPoints.Append(new idVec3(v)); + dirty = true; + } + + void addPoint(float x, float y, float z) { + controlPoints.Append(new idVec3(x, y, z)); + dirty = true; + } + + void updateSelection(const idVec3 &move); + + void startEdit() { + editMode = true; + } + + void stopEdit() { + editMode = false; + } + + void buildSpline(); + + void setGranularity(float f) { + granularity = f; + } + + float getGranularity() { + return granularity; + } + + int numPoints() { + return controlPoints.Num(); + } + + idVec3 *getPoint(int index) { + assert(index >= 0 && index < controlPoints.Num()); + return controlPoints[index]; + } + + idVec3 *getSegmentPoint(int index) { + assert(index >= 0 && index < splinePoints.Num()); + return splinePoints[index]; + } + + + void setSegmentTime(int index, int time) { + assert(index >= 0 && index < splinePoints.Num()); + splineTime[index] = time; + } + + int getSegmentTime(int index) { + assert(index >= 0 && index < splinePoints.Num()); + return (int)splineTime[index]; + } + void addSegmentTime(int index, int time) { + assert(index >= 0 && index < splinePoints.Num()); + splineTime[index] += time; + } + + float totalDistance(); + + static idVec3 zero; + + int getActiveSegment() { + return activeSegment; + } + + void setActiveSegment(int i) { + //assert(i >= 0 && (splinePoints.Num() > 0 && i < splinePoints.Num())); + activeSegment = i; + } + + int numSegments() { + return splinePoints.Num(); + } + + void setColors(idVec3 &path, idVec3 &segment, idVec3 &control, idVec3 &active) { + pathColor = path; + segmentColor = segment; + controlColor = control; + activeColor = active; + } + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + bool validTime() { + if (dirty) { + buildSpline(); + } + // gcc doesn't allow static casting away from bools + // why? I've no idea... + return (bool)(splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num()); + } + + void setTime(long t) { + time = t; + } + + void setBaseTime(long t) { + baseTime = t; + } + +protected: + idStr name; + float calcSpline(int step, float tension); + idList<idVec3*> controlPoints; + idList<idVec3*> splinePoints; + idList<double> splineTime; + idVec3 *selected; + idVec3 pathColor, segmentColor, controlColor, activeColor; + float granularity; + bool editMode; + bool dirty; + int activeSegment; + long baseTime; + long time; + friend class idCamera; +}; + +// time in milliseconds +// velocity where 1.0 equal rough walking speed +struct idVelocity { + idVelocity(long start, long duration, float s) { + startTime = start; + time = duration; + speed = s; + } + long startTime; + long time; + float speed; +}; + +// can either be a look at or origin position for a camera +// +class idCameraPosition : public idPointListInterface { +public: + + virtual void clearVelocities() { + for (int i = 0; i < velocities.Num(); i++) { + delete velocities[i]; + velocities[i] = NULL; + } + velocities.Clear(); + } + + virtual void clear() { + editMode = false; + clearVelocities(); + } + + idCameraPosition(const char *p) { + name = p; + } + + idCameraPosition() { + time = 0; + name = "position"; + } + + idCameraPosition(long t) { + time = t; + } + + virtual ~idCameraPosition() { + clear(); + } + + + // this can be done with RTTI syntax but i like the derived classes setting a type + // makes serialization a bit easier to see + // + enum positionType { + FIXED = 0x00, + INTERPOLATED, + SPLINE, + POSITION_COUNT + }; + + + virtual void start(long t) { + startTime = t; + } + + long getTime() { + return time; + } + + virtual void setTime(long t) { + time = t; + } + + float getBaseVelocity() { + return baseVelocity; + } + + float getVelocity(long t) { + long check = t - startTime; + for (int i = 0; i < velocities.Num(); i++) { + if (check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time) { + return velocities[i]->speed; + } + } + return baseVelocity; + } + + void addVelocity(long start, long duration, float speed) { + velocities.Append(new idVelocity(start, duration, speed)); + } + + virtual const idVec3 *getPosition(long t) { + assert(true); + return NULL; + } + + virtual void draw(bool editMode) {}; + + virtual void parse(const char *(*text)) {}; + virtual void write(fileHandle_t file, const char *name); + virtual bool parseToken(const char *key, const char *(*text)); + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + virtual void startEdit() { + editMode = true; + } + + virtual void stopEdit() { + editMode = false; + } + + virtual void draw() {}; + + const char *typeStr() { + return positionStr[static_cast<int>(type)]; + } + + void calcVelocity(float distance) { + float secs = (float)time / 1000; + baseVelocity = distance / secs; + } + +protected: + static const char* positionStr[POSITION_COUNT]; + long startTime; + long time; + idCameraPosition::positionType type; + idStr name; + bool editMode; + idList<idVelocity*> velocities; + float baseVelocity; +}; + +class idFixedPosition : public idCameraPosition { +public: + + void init() { + pos.Zero(); + type = idCameraPosition::FIXED; + } + + idFixedPosition() : idCameraPosition() { + init(); + } + + idFixedPosition(idVec3 p) : idCameraPosition() { + init(); + pos = p; + } + + virtual void addPoint(const idVec3 &v) { + pos = v; + } + + virtual void addPoint(const float x, const float y, const float z) { + pos.set(x, y, z); + } + + + ~idFixedPosition() { + } + + virtual const idVec3 *getPosition(long t) { + return &pos; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return 1; + } + + virtual idVec3 *getPoint(int index) { + if (index != 0) { + assert(true); + }; + return &pos; + } + + virtual void draw(bool editMode) { + glLabeledPoint(blue, pos, (editMode) ? 5 : 3, "Fixed point"); + } + +protected: + idVec3 pos; +}; + +class idInterpolatedPosition : public idCameraPosition { +public: + + void init() { + type = idCameraPosition::INTERPOLATED; + first = true; + startPos.Zero(); + endPos.Zero(); + } + + idInterpolatedPosition() : idCameraPosition() { + init(); + } + + idInterpolatedPosition(idVec3 start, idVec3 end, long time) : idCameraPosition(time) { + init(); + startPos = start; + endPos = end; + } + + ~idInterpolatedPosition() { + } + + virtual const idVec3 *getPosition(long t); + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return 2; + } + + virtual idVec3 *getPoint(int index) { + assert(index >= 0 && index < 2); + if (index == 0) { + return &startPos; + } + return &endPos; + } + + virtual void addPoint(const float x, const float y, const float z) { + if (first) { + startPos.set(x, y, z); + first = false; + } else { + endPos.set(x, y, z); + first = true; + } + } + + virtual void addPoint(const idVec3 &v) { + if (first) { + startPos = v; + first = false; + } else { + endPos = v; + first = true; + } + } + + virtual void draw(bool editMode) { + glLabeledPoint(blue, startPos, (editMode) ? 5 : 3, "Start interpolated"); + glLabeledPoint(blue, endPos, (editMode) ? 5 : 3, "End interpolated"); + qglBegin(GL_LINES); + qglVertex3fv(startPos); + qglVertex3fv(endPos); + qglEnd(); + } + + virtual void start(long t) { + idCameraPosition::start(t); + lastTime = startTime; + distSoFar = 0.0; + idVec3 temp = startPos; + temp -= endPos; + calcVelocity(temp.Length()); + } + +protected: + bool first; + idVec3 startPos; + idVec3 endPos; + long lastTime; + float distSoFar; +}; + +class idSplinePosition : public idCameraPosition { +public: + + void init() { + type = idCameraPosition::SPLINE; + } + + idSplinePosition() : idCameraPosition() { + init(); + } + + idSplinePosition(long time) : idCameraPosition(time) { + init(); + } + + ~idSplinePosition() { + } + + virtual void start(long t) { + idCameraPosition::start(t); + target.initPosition(t, time); + lastTime = startTime; + distSoFar = 0.0; + calcVelocity(target.totalDistance()); + } + + //virtual const idVec3 *getPosition(long t) { + // return target.getPosition(t); + //} + virtual const idVec3 *getPosition(long t); + + + //virtual const idVec3 *getPosition(long t) const { + + void addControlPoint(idVec3 &v) { + target.addPoint(v); + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + virtual int numPoints() { + return target.numPoints(); + } + + virtual idVec3 *getPoint(int index) { + return target.getPoint(index); + } + + virtual void addPoint(const idVec3 &v) { + target.addPoint(v); + } + + virtual void addPoint(const float x, const float y, const float z) { + target.addPoint(x, y, z); + } + + virtual void draw(bool editMode) { + target.draw(editMode); + } + + virtual void updateSelection(const idVec3 &move) { + idCameraPosition::updateSelection(move); + target.buildSpline(); + } + +protected: + idSplineList target; + long lastTime; + float distSoFar; +}; + +class idCameraFOV { +public: + + idCameraFOV() { + time = 0; + length = 0; + fov = 90; + } + + idCameraFOV(int v) { + time = 0; + length = 0; + fov = v; + } + + idCameraFOV(int s, int e, long t) { + startFOV = s; + endFOV = e; + length = t; + } + + + ~idCameraFOV(){} + + void setFOV(float f) { + fov = f; + } + + float getFOV(long t) { + if (length) { + float percent = (t - startTime) / length; + if (percent < 0.0) { + percent = 0.0; + } else if (percent > 1.0) { + percent = 1.0; + } + float temp = endFOV - startFOV; + temp *= percent; + fov = startFOV + temp; + + if (percent == 1.0) { + length = 0.0; + } + } + return fov; + } + + void start(long t) { + startTime = t; + } + + void reset(float startfov, float endfov, int start, float len) { + startFOV = startfov; + endFOV = endfov; + startTime = start; + length = len * 1000; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + +protected: + float fov; + float startFOV; + float endFOV; + int startTime; + int time; + float length; +}; + + + + +class idCameraEvent { +public: // parameters + enum eventType { + 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 + }; + + static const char* eventStr[EVENT_COUNT]; + + idCameraEvent() { + paramStr = ""; + type = EVENT_NA; + time = 0; + } + + idCameraEvent(eventType t, const char *param, long n) { + type = t; + paramStr = param; + time = n; + } + + ~idCameraEvent() {}; + + eventType getType() { + return type; + } + + const char *typeStr() { + return eventStr[static_cast<int>(type)]; + } + + const char *getParam() { + return paramStr.c_str(); + } + + long getTime() { + return time; + } + + void setTime(long n) { + time = n; + } + + void parse(const char *(*text)); + void write(fileHandle_t file, const char *name); + + void setTriggered(bool b) { + triggered = b; + } + + bool getTriggered() { + return triggered; + } + +protected: + eventType type; + idStr paramStr; + long time; + bool triggered; + +}; + +class idCameraDef { +public: + + void clear() { + currentCameraPosition = 0; + cameraRunning = false; + lastDirection.Zero(); + baseTime = 30; + activeTarget = 0; + name = "camera01"; + fov.setFOV(90); + int i; + for (i = 0; i < targetPositions.Num(); i++) { + delete targetPositions[i]; + } + for (i = 0; i < events.Num(); i++) { + delete events[i]; + } + delete cameraPosition; + cameraPosition = NULL; + events.Clear(); + targetPositions.Clear(); + } + + idCameraPosition *startNewCamera(idCameraPosition::positionType type) { + clear(); + if (type == idCameraPosition::SPLINE) { + cameraPosition = new idSplinePosition(); + } else if (type == idCameraPosition::INTERPOLATED) { + cameraPosition = new idInterpolatedPosition(); + } else { + cameraPosition = new idFixedPosition(); + } + return cameraPosition; + } + + idCameraDef() { + cameraPosition = NULL; + clear(); + } + + ~idCameraDef() { + clear(); + } + + void addEvent(idCameraEvent::eventType t, const char *param, long time); + + void addEvent(idCameraEvent *event); + + void removeEvent( int index); + + static int sortEvents(const void *p1, const void *p2); + + int numEvents() { + return events.Num(); + } + + idCameraEvent *getEvent(int index) { + assert(index >= 0 && index < events.Num()); + return events[index]; + } + + void parse(const char *(*text)); + bool load(const char *filename); + void save(const char *filename); + + void buildCamera(); + + //idSplineList *getcameraPosition() { + // return &cameraPosition; + //} + + static idCameraPosition *newFromType(idCameraPosition::positionType t) { + switch (t) { + case idCameraPosition::FIXED : return new idFixedPosition(); + case idCameraPosition::INTERPOLATED : return new idInterpolatedPosition(); + case idCameraPosition::SPLINE : return new idSplinePosition(); + default: + break; + }; + return NULL; + } + + void addTarget(const char *name, idCameraPosition::positionType type); + + idCameraPosition *getActiveTarget() { + if (targetPositions.Num() == 0) { + addTarget(NULL, idCameraPosition::FIXED); + } + return targetPositions[activeTarget]; + } + + idCameraPosition *getActiveTarget(int index) { + if (targetPositions.Num() == 0) { + addTarget(NULL, idCameraPosition::FIXED); + return targetPositions[0]; + } + return targetPositions[index]; + } + + int numTargets() { + return targetPositions.Num(); + } + + + void setActiveTargetByName(const char *name) { + for (int i = 0; i < targetPositions.Num(); i++) { + if (Q_stricmp(name, targetPositions[i]->getName()) == 0) { + setActiveTarget(i); + return; + } + } + } + + void setActiveTarget(int index) { + assert(index >= 0 && index < targetPositions.Num()); + activeTarget = index; + } + + void setRunning(bool b) { + cameraRunning = b; + } + + void setBaseTime(float f) { + baseTime = f; + } + + float getBaseTime() { + return baseTime; + } + + float getTotalTime() { + return totalTime; + } + + void startCamera(long t); + void stopCamera() { + cameraRunning = true; + } + void getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fv); + + bool getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv); + bool getCameraInfo(long time, float *origin, float *direction, float *fv) { + idVec3 org, dir; + org[0] = origin[0]; + org[1] = origin[1]; + org[2] = origin[2]; + dir[0] = direction[0]; + dir[1] = direction[1]; + dir[2] = direction[2]; + bool b = getCameraInfo(time, org, dir, fv); + origin[0] = org[0]; + origin[1] = org[1]; + origin[2] = org[2]; + direction[0] = dir[0]; + direction[1] = dir[1]; + direction[2] = dir[2]; + return b; + } + + void draw(bool editMode) { + // gcc doesn't allow casting away from bools + // why? I've no idea... + if (cameraPosition) { + cameraPosition->draw((bool)((editMode || cameraRunning) && cameraEdit)); + int count = targetPositions.Num(); + for (int i = 0; i < count; i++) { + targetPositions[i]->draw((bool)((editMode || cameraRunning) && i == activeTarget && !cameraEdit)); + } + } + } + +/* + int numSegments() { + if (cameraEdit) { + return cameraPosition.numSegments(); + } + return getTargetSpline()->numSegments(); + } + + int getActiveSegment() { + if (cameraEdit) { + return cameraPosition.getActiveSegment(); + } + return getTargetSpline()->getActiveSegment(); + } + + void setActiveSegment(int i) { + if (cameraEdit) { + cameraPosition.setActiveSegment(i); + } else { + getTargetSpline()->setActiveSegment(i); + } + } +*/ + int numPoints() { + if (cameraEdit) { + return cameraPosition->numPoints(); + } + return getActiveTarget()->numPoints(); + } + + const idVec3 *getPoint(int index) { + if (cameraEdit) { + return cameraPosition->getPoint(index); + } + return getActiveTarget()->getPoint(index); + } + + void stopEdit() { + editMode = false; + if (cameraEdit) { + cameraPosition->stopEdit(); + } else { + getActiveTarget()->stopEdit(); + } + } + + void startEdit(bool camera) { + cameraEdit = camera; + if (camera) { + cameraPosition->startEdit(); + for (int i = 0; i < targetPositions.Num(); i++) { + targetPositions[i]->stopEdit(); + } + } else { + getActiveTarget()->startEdit(); + cameraPosition->stopEdit(); + } + editMode = true; + } + + bool waitEvent(int index); + + const char *getName() { + return name.c_str(); + } + + void setName(const char *p) { + name = p; + } + + idCameraPosition *getPositionObj() { + if (cameraPosition == NULL) { + cameraPosition = new idFixedPosition(); + } + return cameraPosition; + } + +protected: + idStr name; + int currentCameraPosition; + idVec3 lastDirection; + bool cameraRunning; + idCameraPosition *cameraPosition; + idList<idCameraPosition*> targetPositions; + idList<idCameraEvent*> events; + idCameraFOV fov; + int activeTarget; + float totalTime; + float baseTime; + long startTime; + + bool cameraEdit; + bool editMode; +}; + +extern bool g_splineMode; + +extern idCameraDef *g_splineList; + + +#endif diff --git a/libs/splines/util_list.h b/libs/splines/util_list.h index 7dc72491..7776e87c 100644 --- a/libs/splines/util_list.h +++ b/libs/splines/util_list.h @@ -1,346 +1,346 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __UTIL_LIST_H__ -#define __UTIL_LIST_H__ - -#include <stdlib.h> -#include <assert.h> - -template< class type > -class idList { -private: - int m_num; - int m_size; - int m_granularity; - type *m_list; - -public: - idList( int granularity = 16 ); - ~idList<type>(); - void Clear( void ); - int Num( void ); - void SetNum( int num ); - void SetGranularity( int granularity ); - void Condense( void ); - int Size( void ); - void Resize( int size ); - type operator[]( int index ) const; - type &operator[]( int index ); - int Append( type const & obj ); - int AddUnique( type const & obj ); - type *Find( type const & obj, int *index = NULL ); - bool RemoveIndex( int index ); - bool Remove( type const & obj ); - typedef int cmp_t(const void *, const void *); - void Sort( cmp_t *compare ); -}; - -/* -================ -idList<type>::idList( int ) -================ -*/ -template< class type > -inline idList<type>::idList( int granularity ) { - assert( granularity > 0 ); - - m_list = NULL; - m_granularity = granularity; - Clear(); -} - -/* -================ -idList<type>::~idList<type> -================ -*/ -template< class type > -inline idList<type>::~idList() { - Clear(); -} - -/* -================ -idList<type>::Clear -================ -*/ -template< class type > -inline void idList<type>::Clear( void ) { - if ( m_list ) { - delete[] m_list; - } - - m_list = NULL; - m_num = 0; - m_size = 0; -} - -/* -================ -idList<type>::Num -================ -*/ -template< class type > -inline int idList<type>::Num( void ) { - return m_num; -} - -/* -================ -idList<type>::SetNum -================ -*/ -template< class type > -inline void idList<type>::SetNum( int num ) { - assert( num >= 0 ); - if ( num > m_size ) { - // resize it up to the closest level of granularity - Resize( ( ( num + m_granularity - 1 ) / m_granularity ) * m_granularity ); - } - m_num = num; -} - -/* -================ -idList<type>::SetGranularity -================ -*/ -template< class type > -inline void idList<type>::SetGranularity( int granularity ) { - int newsize; - - assert( granularity > 0 ); - m_granularity = granularity; - - if ( m_list ) { - // resize it to the closest level of granularity - newsize = ( ( m_num + m_granularity - 1 ) / m_granularity ) * m_granularity; - if ( newsize != m_size ) { - Resize( newsize ); - } - } -} - -/* -================ -idList<type>::Condense - -Resizes the array to exactly the number of elements it contains -================ -*/ -template< class type > -inline void idList<type>::Condense( void ) { - if ( m_list ) { - if ( m_num ) { - Resize( m_num ); - } else { - Clear(); - } - } -} - -/* -================ -idList<type>::Size -================ -*/ -template< class type > -inline int idList<type>::Size( void ) { - return m_size; -} - -/* -================ -idList<type>::Resize -================ -*/ -template< class type > -inline void idList<type>::Resize( int size ) { - type *temp; - int i; - - assert( size > 0 ); - - if ( size <= 0 ) { - Clear(); - return; - } - - temp = m_list; - m_size = size; - if ( m_size < m_num ) { - m_num = m_size; - } - - m_list = new type[ m_size ]; - for( i = 0; i < m_num; i++ ) { - m_list[ i ] = temp[ i ]; - } - - if ( temp ) { - delete[] temp; - } -} - -/* -================ -idList<type>::operator[] const -================ -*/ -template< class type > -inline type idList<type>::operator[]( int index ) const { - assert( index >= 0 ); - assert( index < m_num ); - - return m_list[ index ]; -} - -/* -================ -idList<type>::operator[] -================ -*/ -template< class type > -inline type &idList<type>::operator[]( int index ) { - assert( index >= 0 ); - assert( index < m_num ); - - return m_list[ index ]; -} - -/* -================ -idList<type>::Append -================ -*/ -template< class type > -inline int idList<type>::Append( type const & obj ) { - if ( !m_list ) { - Resize( m_granularity ); - } - - if ( m_num == m_size ) { - Resize( m_size + m_granularity ); - } - - m_list[ m_num ] = obj; - m_num++; - - return m_num - 1; -} - -/* -================ -idList<type>::AddUnique -================ -*/ -template< class type > -inline int idList<type>::AddUnique( type const & obj ) { - int index; - - if ( !Find( obj, &index ) ) { - index = Append( obj ); - } - - return index; -} - -/* -================ -idList<type>::Find -================ -*/ -template< class type > -inline type *idList<type>::Find( type const & obj, int *index ) { - int i; - - for( i = 0; i < m_num; i++ ) { - if ( m_list[ i ] == obj ) { - if ( index ) { - *index = i; - } - return &m_list[ i ]; - } - } - - return NULL; -} - -/* -================ -idList<type>::RemoveIndex -================ -*/ -template< class type > -inline bool idList<type>::RemoveIndex( int index ) { - int i; - - if ( !m_list || !m_num ) { - return false; - } - - assert( index >= 0 ); - assert( index < m_num ); - - if ( ( index < 0 ) || ( index >= m_num ) ) { - return false; - } - - m_num--; - for( i = index; i < m_num; i++ ) { - m_list[ i ] = m_list[ i + 1 ]; - } - - return true; -} - -/* -================ -idList<type>::Remove -================ -*/ -template< class type > -inline bool idList<type>::Remove( type const & obj ) { - int index; - - if ( Find( obj, &index ) ) { - return RemoveIndex( index ); - } - - return false; -} - -/* -================ -idList<type>::Sort -================ -*/ -template< class type > -inline void idList<type>::Sort( cmp_t *compare ) { - if ( !m_list ) { - return; - } - - qsort( ( void * )m_list, ( size_t )m_num, sizeof( type ), compare ); -} - -#endif /* !__UTIL_LIST_H__ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __UTIL_LIST_H__ +#define __UTIL_LIST_H__ + +#include <stdlib.h> +#include <assert.h> + +template< class type > +class idList { +private: + int m_num; + int m_size; + int m_granularity; + type *m_list; + +public: + idList( int granularity = 16 ); + ~idList<type>(); + void Clear( void ); + int Num( void ); + void SetNum( int num ); + void SetGranularity( int granularity ); + void Condense( void ); + int Size( void ); + void Resize( int size ); + type operator[]( int index ) const; + type &operator[]( int index ); + int Append( type const & obj ); + int AddUnique( type const & obj ); + type *Find( type const & obj, int *index = NULL ); + bool RemoveIndex( int index ); + bool Remove( type const & obj ); + typedef int cmp_t(const void *, const void *); + void Sort( cmp_t *compare ); +}; + +/* +================ +idList<type>::idList( int ) +================ +*/ +template< class type > +inline idList<type>::idList( int granularity ) { + assert( granularity > 0 ); + + m_list = NULL; + m_granularity = granularity; + Clear(); +} + +/* +================ +idList<type>::~idList<type> +================ +*/ +template< class type > +inline idList<type>::~idList() { + Clear(); +} + +/* +================ +idList<type>::Clear +================ +*/ +template< class type > +inline void idList<type>::Clear( void ) { + if ( m_list ) { + delete[] m_list; + } + + m_list = NULL; + m_num = 0; + m_size = 0; +} + +/* +================ +idList<type>::Num +================ +*/ +template< class type > +inline int idList<type>::Num( void ) { + return m_num; +} + +/* +================ +idList<type>::SetNum +================ +*/ +template< class type > +inline void idList<type>::SetNum( int num ) { + assert( num >= 0 ); + if ( num > m_size ) { + // resize it up to the closest level of granularity + Resize( ( ( num + m_granularity - 1 ) / m_granularity ) * m_granularity ); + } + m_num = num; +} + +/* +================ +idList<type>::SetGranularity +================ +*/ +template< class type > +inline void idList<type>::SetGranularity( int granularity ) { + int newsize; + + assert( granularity > 0 ); + m_granularity = granularity; + + if ( m_list ) { + // resize it to the closest level of granularity + newsize = ( ( m_num + m_granularity - 1 ) / m_granularity ) * m_granularity; + if ( newsize != m_size ) { + Resize( newsize ); + } + } +} + +/* +================ +idList<type>::Condense + +Resizes the array to exactly the number of elements it contains +================ +*/ +template< class type > +inline void idList<type>::Condense( void ) { + if ( m_list ) { + if ( m_num ) { + Resize( m_num ); + } else { + Clear(); + } + } +} + +/* +================ +idList<type>::Size +================ +*/ +template< class type > +inline int idList<type>::Size( void ) { + return m_size; +} + +/* +================ +idList<type>::Resize +================ +*/ +template< class type > +inline void idList<type>::Resize( int size ) { + type *temp; + int i; + + assert( size > 0 ); + + if ( size <= 0 ) { + Clear(); + return; + } + + temp = m_list; + m_size = size; + if ( m_size < m_num ) { + m_num = m_size; + } + + m_list = new type[ m_size ]; + for( i = 0; i < m_num; i++ ) { + m_list[ i ] = temp[ i ]; + } + + if ( temp ) { + delete[] temp; + } +} + +/* +================ +idList<type>::operator[] const +================ +*/ +template< class type > +inline type idList<type>::operator[]( int index ) const { + assert( index >= 0 ); + assert( index < m_num ); + + return m_list[ index ]; +} + +/* +================ +idList<type>::operator[] +================ +*/ +template< class type > +inline type &idList<type>::operator[]( int index ) { + assert( index >= 0 ); + assert( index < m_num ); + + return m_list[ index ]; +} + +/* +================ +idList<type>::Append +================ +*/ +template< class type > +inline int idList<type>::Append( type const & obj ) { + if ( !m_list ) { + Resize( m_granularity ); + } + + if ( m_num == m_size ) { + Resize( m_size + m_granularity ); + } + + m_list[ m_num ] = obj; + m_num++; + + return m_num - 1; +} + +/* +================ +idList<type>::AddUnique +================ +*/ +template< class type > +inline int idList<type>::AddUnique( type const & obj ) { + int index; + + if ( !Find( obj, &index ) ) { + index = Append( obj ); + } + + return index; +} + +/* +================ +idList<type>::Find +================ +*/ +template< class type > +inline type *idList<type>::Find( type const & obj, int *index ) { + int i; + + for( i = 0; i < m_num; i++ ) { + if ( m_list[ i ] == obj ) { + if ( index ) { + *index = i; + } + return &m_list[ i ]; + } + } + + return NULL; +} + +/* +================ +idList<type>::RemoveIndex +================ +*/ +template< class type > +inline bool idList<type>::RemoveIndex( int index ) { + int i; + + if ( !m_list || !m_num ) { + return false; + } + + assert( index >= 0 ); + assert( index < m_num ); + + if ( ( index < 0 ) || ( index >= m_num ) ) { + return false; + } + + m_num--; + for( i = index; i < m_num; i++ ) { + m_list[ i ] = m_list[ i + 1 ]; + } + + return true; +} + +/* +================ +idList<type>::Remove +================ +*/ +template< class type > +inline bool idList<type>::Remove( type const & obj ) { + int index; + + if ( Find( obj, &index ) ) { + return RemoveIndex( index ); + } + + return false; +} + +/* +================ +idList<type>::Sort +================ +*/ +template< class type > +inline void idList<type>::Sort( cmp_t *compare ) { + if ( !m_list ) { + return; + } + + qsort( ( void * )m_list, ( size_t )m_num, sizeof( type ), compare ); +} + +#endif /* !__UTIL_LIST_H__ */ diff --git a/libs/splines/util_str.h b/libs/splines/util_str.h index 26dfa42d..0ce1ecb4 100644 --- a/libs/splines/util_str.h +++ b/libs/splines/util_str.h @@ -1,817 +1,817 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -//need to rewrite this - -#ifndef __UTIL_STR_H__ -#define __UTIL_STR_H__ - -#include <assert.h> -#include <string.h> -#include <stdio.h> - -#ifdef _WIN32 -#pragma warning(disable : 4710) // function 'blah' not inlined -#endif - -void TestStringClass (); - -class strdata - { - public: - strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} - ~strdata () - { - if ( data ) - delete [] data; - } - - void AddRef () { refcount++; } - bool DelRef () // True if killed - { - refcount--; - if ( refcount < 0 ) - { - delete this; - return true; - } - - return false; - } - - int len; - int refcount; - char *data; - int alloced; - }; - -class idStr { -protected: - strdata *m_data; - void EnsureAlloced ( int, bool keepold = true ); - void EnsureDataWritable (); - -public: - ~idStr(); - idStr(); - idStr( const char *text ); - idStr( const idStr& string ); - idStr( const idStr string, int start, int end ); - idStr( const char ch ); - idStr( const int num ); - idStr( const float num ); - idStr( const unsigned num ); - int length( void ) const; - int allocated( void ) const; - const char * c_str( void ) const; - - void append( const char *text ); - void append( const idStr& text ); - char operator[]( int index ) const; - char& operator[]( int index ); - - void operator=( const idStr& text ); - void operator=( const char *text ); - - friend idStr operator+( const idStr& a, const idStr& b ); - friend idStr operator+( const idStr& a, const char *b ); - friend idStr operator+( const char *a, const idStr& b ); - - friend idStr operator+( const idStr& a, const float b ); - friend idStr operator+( const idStr& a, const int b ); - friend idStr operator+( const idStr& a, const unsigned b ); - friend idStr operator+( const idStr& a, const bool b ); - friend idStr operator+( const idStr& a, const char b ); - - idStr& operator+=( const idStr& a ); - idStr& operator+=( const char *a ); - idStr& operator+=( const float a ); - idStr& operator+=( const char a ); - idStr& operator+=( const int a ); - idStr& operator+=( const unsigned a ); - idStr& operator+=( const bool a ); - - friend bool operator==( const idStr& a, const idStr& b ); - friend bool operator==( const idStr& a, const char *b ); - friend bool operator==( const char *a, const idStr& b ); - - friend bool operator!=( const idStr& a, const idStr& b ); - friend bool operator!=( const idStr& a, const char *b ); - friend bool operator!=( const char *a, const idStr& b ); - - operator const char * () const; - operator const char * (); - - int icmpn( const char *text, int n ) const; - int icmpn( const idStr& text, int n ) const; - int icmp( const char *text ) const; - int icmp( const idStr& text ) const; - int cmpn( const char *text, int n ) const; - int cmpn( const idStr& text, int n ) const; - int cmp( const char *text ) const; - int cmp( const idStr& text ) const; - - void tolower( void ); - void toupper( void ); - - static char *tolower( char *s1 ); - static char *toupper( char *s1 ); - - static int icmpn( const char *s1, const char *s2, int n ); - static int icmp( const char *s1, const char *s2 ); - static int cmpn( const char *s1, const char *s2, int n ); - static int cmp( const char *s1, const char *s2 ); - - static void snprintf ( char *dst, int size, const char *fmt, ... ); - - static bool isNumeric( const char *str ); - bool isNumeric( void ) const; - - void CapLength ( int ); - - void BackSlashesToSlashes (); - -}; - -inline idStr::~idStr() - { - if ( m_data ) - { - m_data->DelRef (); - m_data = NULL; - } - } - -inline idStr::idStr() : m_data ( NULL ) - { - EnsureAlloced ( 1 ); - m_data->data[ 0 ] = 0; - } - -inline idStr::idStr - ( - const char *text - ) : m_data ( NULL ) - - { - int len; - - assert( text ); - - if ( text ) - { - len = strlen( text ); - EnsureAlloced ( len + 1 ); - strcpy( m_data->data, text ); - m_data->len = len; - } - else - { - EnsureAlloced ( 1 ); - m_data->data[ 0 ] = 0; - m_data->len = 0; - } - } - -inline idStr::idStr - ( - const idStr& text - ) : m_data ( NULL ) - - { - m_data = text.m_data; - m_data->AddRef (); - } - -inline idStr::idStr - ( - const idStr text, - int start, - int end - ) : m_data ( NULL ) - - { - int i; - int len; - - if ( end > text.length() ) - { - end = text.length(); - } - - if ( start > text.length() ) - { - start = text.length(); - } - - len = end - start; - if ( len < 0 ) - { - len = 0; - } - - EnsureAlloced ( len + 1 ); - - for( i = 0; i < len; i++ ) - { - m_data->data[ i ] = text[ start + i ]; - } - - m_data->data[ len ] = 0; - m_data->len = len; - } - -inline idStr::idStr - ( - const char ch - ) : m_data ( NULL ) - - { - EnsureAlloced ( 2 ); - - m_data->data[ 0 ] = ch; - m_data->data[ 1 ] = 0; - m_data->len = 1; - } - -inline idStr::idStr - ( - const float num - ) : m_data ( NULL ) - - { - char text[ 32 ]; - int len; - - sprintf( text, "%.3f", num ); - len = strlen( text ); - EnsureAlloced( len + 1 ); - strcpy( m_data->data, text ); - m_data->len = len; - } - -inline idStr::idStr - ( - const int num - ) : m_data ( NULL ) - - { - char text[ 32 ]; - int len; - - sprintf( text, "%d", num ); - len = strlen( text ); - EnsureAlloced( len + 1 ); - strcpy( m_data->data, text ); - m_data->len = len; - } - -inline idStr::idStr - ( - const unsigned num - ) : m_data ( NULL ) - - { - char text[ 32 ]; - int len; - - sprintf( text, "%u", num ); - len = strlen( text ); - EnsureAlloced( len + 1 ); - strcpy( m_data->data, text ); - m_data->len = len; - } - -inline int idStr::length( void ) const - { - return ( m_data != NULL ) ? m_data->len : 0; - } - -inline int idStr::allocated( void ) const - { - return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0; - } - -inline const char *idStr::c_str( void ) const - { - assert( m_data ); - - return m_data->data; - } - -inline void idStr::append - ( - const char *text - ) - - { - int len; - - assert( text ); - - if ( text ) - { - len = length() + strlen( text ); - EnsureAlloced( len + 1 ); - - strcat( m_data->data, text ); - m_data->len = len; - } - } - -inline void idStr::append - ( - const idStr& text - ) - - { - int len; - - len = length() + text.length(); - EnsureAlloced ( len + 1 ); - - strcat ( m_data->data, text.c_str () ); - m_data->len = len; - } - -inline char idStr::operator[]( int index ) const - { - assert ( m_data ); - - if ( !m_data ) - return 0; - - // don't include the '/0' in the test, because technically, it's out of bounds - assert( ( index >= 0 ) && ( index < m_data->len ) ); - - // In release mode, give them a null character - // don't include the '/0' in the test, because technically, it's out of bounds - if ( ( index < 0 ) || ( index >= m_data->len ) ) - { - return 0; - } - - return m_data->data[ index ]; - } - -inline char& idStr::operator[] - ( - int index - ) - - { - // Used for result for invalid indices - static char dummy = 0; - assert ( m_data ); - - // We don't know if they'll write to it or not - // if it's not a const object - EnsureDataWritable (); - - if ( !m_data ) - return dummy; - - // don't include the '/0' in the test, because technically, it's out of bounds - assert( ( index >= 0 ) && ( index < m_data->len ) ); - - // In release mode, let them change a safe variable - // don't include the '/0' in the test, because technically, it's out of bounds - if ( ( index < 0 ) || ( index >= m_data->len ) ) - { - return dummy; - } - - return m_data->data[ index ]; - } - -inline void idStr::operator= - ( - const idStr& text - ) - - { - // adding the reference before deleting our current reference prevents - // us from deleting our string if we are copying from ourself - text.m_data->AddRef(); - m_data->DelRef(); - m_data = text.m_data; - } - -inline void idStr::operator= - ( - const char *text - ) - - { - int len; - - assert( text ); - - if ( !text ) - { - // safe behaviour if NULL - EnsureAlloced ( 1, false ); - m_data->data[0] = 0; - m_data->len = 0; - return; - } - - if ( !m_data ) - { - len = strlen ( text ); - EnsureAlloced( len + 1, false ); - strcpy ( m_data->data, text ); - m_data->len = len; - return; - } - - if ( text == m_data->data ) - return; // Copying same thing. Punt. - - // If we alias and I don't do this, I could corrupt other strings... This - // will get called with EnsureAlloced anyway - EnsureDataWritable (); - - // Now we need to check if we're aliasing.. - if ( text >= m_data->data && text <= m_data->data + m_data->len ) - { - // Great, we're aliasing. We're copying from inside ourselves. - // This means that I don't have to ensure that anything is alloced, - // though I'll assert just in case. - int diff = text - m_data->data; - int i; - - assert ( strlen ( text ) < (unsigned) m_data->len ); - - for ( i = 0; text[i]; i++ ) - { - m_data->data[i] = text[i]; - } - - m_data->data[i] = 0; - - m_data->len -= diff; - - return; - } - - len = strlen( text ); - EnsureAlloced ( len + 1, false ); - strcpy( m_data->data, text ); - m_data->len = len; - } - -inline idStr operator+ - ( - const idStr& a, - const idStr& b - ) - - { - idStr result( a ); - - result.append( b ); - - return result; - } - -inline idStr operator+ - ( - const idStr& a, - const char *b - ) - - { - idStr result( a ); - - result.append( b ); - - return result; - } - -inline idStr operator+ - ( - const char *a, - const idStr& b - ) - - { - idStr result( a ); - - result.append( b ); - - return result; - } - -inline idStr operator+ - ( - const idStr& a, - const bool b - ) - - { - idStr result( a ); - - result.append( b ? "true" : "false" ); - - return result; - } - -inline idStr operator+ - ( - const idStr& a, - const char b - ) - - { - char text[ 2 ]; - - text[ 0 ] = b; - text[ 1 ] = 0; - - return a + text; - } - -inline idStr& idStr::operator+= - ( - const idStr& a - ) - - { - append( a ); - return *this; - } - -inline idStr& idStr::operator+= - ( - const char *a - ) - - { - append( a ); - return *this; - } - -inline idStr& idStr::operator+= - ( - const char a - ) - - { - char text[ 2 ]; - - text[ 0 ] = a; - text[ 1 ] = 0; - append( text ); - - return *this; - } - -inline idStr& idStr::operator+= - ( - const bool a - ) - - { - append( a ? "true" : "false" ); - return *this; - } - -inline bool operator== - ( - const idStr& a, - const idStr& b - ) - - { - return ( !strcmp( a.c_str(), b.c_str() ) ); - } - -inline bool operator== - ( - const idStr& a, - const char *b - ) - - { - assert( b ); - if ( !b ) - { - return false; - } - return ( !strcmp( a.c_str(), b ) ); - } - -inline bool operator== - ( - const char *a, - const idStr& b - ) - - { - assert( a ); - if ( !a ) - { - return false; - } - return ( !strcmp( a, b.c_str() ) ); - } - -inline bool operator!= - ( - const idStr& a, - const idStr& b - ) - - { - return !( a == b ); - } - -inline bool operator!= - ( - const idStr& a, - const char *b - ) - - { - return !( a == b ); - } - -inline bool operator!= - ( - const char *a, - const idStr& b - ) - - { - return !( a == b ); - } - -inline int idStr::icmpn - ( - const char *text, - int n - ) const - - { - assert( m_data ); - assert( text ); - - return idStr::icmpn( m_data->data, text, n ); - } - -inline int idStr::icmpn - ( - const idStr& text, - int n - ) const - - { - assert( m_data ); - assert( text.m_data ); - - return idStr::icmpn( m_data->data, text.m_data->data, n ); - } - -inline int idStr::icmp - ( - const char *text - ) const - - { - assert( m_data ); - assert( text ); - - return idStr::icmp( m_data->data, text ); - } - -inline int idStr::icmp - ( - const idStr& text - ) const - - { - assert( c_str () ); - assert( text.c_str () ); - - return idStr::icmp( c_str () , text.c_str () ); - } - -inline int idStr::cmp - ( - const char *text - ) const - - { - assert( m_data ); - assert( text ); - - return idStr::cmp( m_data->data, text ); - } - -inline int idStr::cmp - ( - const idStr& text - ) const - - { - assert( c_str () ); - assert( text.c_str () ); - - return idStr::cmp( c_str () , text.c_str () ); - } - -inline int idStr::cmpn - ( - const char *text, - int n - ) const - - { - assert( c_str () ); - assert( text ); - - return idStr::cmpn( c_str () , text, n ); - } - -inline int idStr::cmpn - ( - const idStr& text, - int n - ) const - - { - assert( c_str () ); - assert( text.c_str () ); - - return idStr::cmpn( c_str () , text.c_str () , n ); - } - -inline void idStr::tolower - ( - void - ) - - { - assert( m_data ); - - EnsureDataWritable (); - - idStr::tolower( m_data->data ); - } - -inline void idStr::toupper - ( - void - ) - - { - assert( m_data ); - - EnsureDataWritable (); - - idStr::toupper( m_data->data ); - } - -inline bool idStr::isNumeric - ( - void - ) const - - { - assert( m_data ); - return idStr::isNumeric( m_data->data ); - } - -inline idStr::operator const char *() { - return c_str(); -} - -inline idStr::operator const char * - ( - void - ) const - - { - return c_str (); - } - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//need to rewrite this + +#ifndef __UTIL_STR_H__ +#define __UTIL_STR_H__ + +#include <assert.h> +#include <string.h> +#include <stdio.h> + +#ifdef _WIN32 +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +void TestStringClass (); + +class strdata + { + public: + strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} + ~strdata () + { + if ( data ) + delete [] data; + } + + void AddRef () { refcount++; } + bool DelRef () // True if killed + { + refcount--; + if ( refcount < 0 ) + { + delete this; + return true; + } + + return false; + } + + int len; + int refcount; + char *data; + int alloced; + }; + +class idStr { +protected: + strdata *m_data; + void EnsureAlloced ( int, bool keepold = true ); + void EnsureDataWritable (); + +public: + ~idStr(); + idStr(); + idStr( const char *text ); + idStr( const idStr& string ); + idStr( const idStr string, int start, int end ); + idStr( const char ch ); + idStr( const int num ); + idStr( const float num ); + idStr( const unsigned num ); + int length( void ) const; + int allocated( void ) const; + const char * c_str( void ) const; + + void append( const char *text ); + void append( const idStr& text ); + char operator[]( int index ) const; + char& operator[]( int index ); + + void operator=( const idStr& text ); + void operator=( const char *text ); + + friend idStr operator+( const idStr& a, const idStr& b ); + friend idStr operator+( const idStr& a, const char *b ); + friend idStr operator+( const char *a, const idStr& b ); + + friend idStr operator+( const idStr& a, const float b ); + friend idStr operator+( const idStr& a, const int b ); + friend idStr operator+( const idStr& a, const unsigned b ); + friend idStr operator+( const idStr& a, const bool b ); + friend idStr operator+( const idStr& a, const char b ); + + idStr& operator+=( const idStr& a ); + idStr& operator+=( const char *a ); + idStr& operator+=( const float a ); + idStr& operator+=( const char a ); + idStr& operator+=( const int a ); + idStr& operator+=( const unsigned a ); + idStr& operator+=( const bool a ); + + friend bool operator==( const idStr& a, const idStr& b ); + friend bool operator==( const idStr& a, const char *b ); + friend bool operator==( const char *a, const idStr& b ); + + friend bool operator!=( const idStr& a, const idStr& b ); + friend bool operator!=( const idStr& a, const char *b ); + friend bool operator!=( const char *a, const idStr& b ); + + operator const char * () const; + operator const char * (); + + int icmpn( const char *text, int n ) const; + int icmpn( const idStr& text, int n ) const; + int icmp( const char *text ) const; + int icmp( const idStr& text ) const; + int cmpn( const char *text, int n ) const; + int cmpn( const idStr& text, int n ) const; + int cmp( const char *text ) const; + int cmp( const idStr& text ) const; + + void tolower( void ); + void toupper( void ); + + static char *tolower( char *s1 ); + static char *toupper( char *s1 ); + + static int icmpn( const char *s1, const char *s2, int n ); + static int icmp( const char *s1, const char *s2 ); + static int cmpn( const char *s1, const char *s2, int n ); + static int cmp( const char *s1, const char *s2 ); + + static void snprintf ( char *dst, int size, const char *fmt, ... ); + + static bool isNumeric( const char *str ); + bool isNumeric( void ) const; + + void CapLength ( int ); + + void BackSlashesToSlashes (); + +}; + +inline idStr::~idStr() + { + if ( m_data ) + { + m_data->DelRef (); + m_data = NULL; + } + } + +inline idStr::idStr() : m_data ( NULL ) + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + } + +inline idStr::idStr + ( + const char *text + ) : m_data ( NULL ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = strlen( text ); + EnsureAlloced ( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + else + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + m_data->len = 0; + } + } + +inline idStr::idStr + ( + const idStr& text + ) : m_data ( NULL ) + + { + m_data = text.m_data; + m_data->AddRef (); + } + +inline idStr::idStr + ( + const idStr text, + int start, + int end + ) : m_data ( NULL ) + + { + int i; + int len; + + if ( end > text.length() ) + { + end = text.length(); + } + + if ( start > text.length() ) + { + start = text.length(); + } + + len = end - start; + if ( len < 0 ) + { + len = 0; + } + + EnsureAlloced ( len + 1 ); + + for( i = 0; i < len; i++ ) + { + m_data->data[ i ] = text[ start + i ]; + } + + m_data->data[ len ] = 0; + m_data->len = len; + } + +inline idStr::idStr + ( + const char ch + ) : m_data ( NULL ) + + { + EnsureAlloced ( 2 ); + + m_data->data[ 0 ] = ch; + m_data->data[ 1 ] = 0; + m_data->len = 1; + } + +inline idStr::idStr + ( + const float num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%.3f", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr::idStr + ( + const int num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%d", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr::idStr + ( + const unsigned num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%u", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline int idStr::length( void ) const + { + return ( m_data != NULL ) ? m_data->len : 0; + } + +inline int idStr::allocated( void ) const + { + return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0; + } + +inline const char *idStr::c_str( void ) const + { + assert( m_data ); + + return m_data->data; + } + +inline void idStr::append + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = length() + strlen( text ); + EnsureAlloced( len + 1 ); + + strcat( m_data->data, text ); + m_data->len = len; + } + } + +inline void idStr::append + ( + const idStr& text + ) + + { + int len; + + len = length() + text.length(); + EnsureAlloced ( len + 1 ); + + strcat ( m_data->data, text.c_str () ); + m_data->len = len; + } + +inline char idStr::operator[]( int index ) const + { + assert ( m_data ); + + if ( !m_data ) + return 0; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, give them a null character + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return 0; + } + + return m_data->data[ index ]; + } + +inline char& idStr::operator[] + ( + int index + ) + + { + // Used for result for invalid indices + static char dummy = 0; + assert ( m_data ); + + // We don't know if they'll write to it or not + // if it's not a const object + EnsureDataWritable (); + + if ( !m_data ) + return dummy; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, let them change a safe variable + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return dummy; + } + + return m_data->data[ index ]; + } + +inline void idStr::operator= + ( + const idStr& text + ) + + { + // adding the reference before deleting our current reference prevents + // us from deleting our string if we are copying from ourself + text.m_data->AddRef(); + m_data->DelRef(); + m_data = text.m_data; + } + +inline void idStr::operator= + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( !text ) + { + // safe behaviour if NULL + EnsureAlloced ( 1, false ); + m_data->data[0] = 0; + m_data->len = 0; + return; + } + + if ( !m_data ) + { + len = strlen ( text ); + EnsureAlloced( len + 1, false ); + strcpy ( m_data->data, text ); + m_data->len = len; + return; + } + + if ( text == m_data->data ) + return; // Copying same thing. Punt. + + // If we alias and I don't do this, I could corrupt other strings... This + // will get called with EnsureAlloced anyway + EnsureDataWritable (); + + // Now we need to check if we're aliasing.. + if ( text >= m_data->data && text <= m_data->data + m_data->len ) + { + // Great, we're aliasing. We're copying from inside ourselves. + // This means that I don't have to ensure that anything is alloced, + // though I'll assert just in case. + int diff = text - m_data->data; + int i; + + assert ( strlen ( text ) < (unsigned) m_data->len ); + + for ( i = 0; text[i]; i++ ) + { + m_data->data[i] = text[i]; + } + + m_data->data[i] = 0; + + m_data->len -= diff; + + return; + } + + len = strlen( text ); + EnsureAlloced ( len + 1, false ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline idStr operator+ + ( + const idStr& a, + const idStr& b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const char *b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const char *a, + const idStr& b + ) + + { + idStr result( a ); + + result.append( b ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const bool b + ) + + { + idStr result( a ); + + result.append( b ? "true" : "false" ); + + return result; + } + +inline idStr operator+ + ( + const idStr& a, + const char b + ) + + { + char text[ 2 ]; + + text[ 0 ] = b; + text[ 1 ] = 0; + + return a + text; + } + +inline idStr& idStr::operator+= + ( + const idStr& a + ) + + { + append( a ); + return *this; + } + +inline idStr& idStr::operator+= + ( + const char *a + ) + + { + append( a ); + return *this; + } + +inline idStr& idStr::operator+= + ( + const char a + ) + + { + char text[ 2 ]; + + text[ 0 ] = a; + text[ 1 ] = 0; + append( text ); + + return *this; + } + +inline idStr& idStr::operator+= + ( + const bool a + ) + + { + append( a ? "true" : "false" ); + return *this; + } + +inline bool operator== + ( + const idStr& a, + const idStr& b + ) + + { + return ( !strcmp( a.c_str(), b.c_str() ) ); + } + +inline bool operator== + ( + const idStr& a, + const char *b + ) + + { + assert( b ); + if ( !b ) + { + return false; + } + return ( !strcmp( a.c_str(), b ) ); + } + +inline bool operator== + ( + const char *a, + const idStr& b + ) + + { + assert( a ); + if ( !a ) + { + return false; + } + return ( !strcmp( a, b.c_str() ) ); + } + +inline bool operator!= + ( + const idStr& a, + const idStr& b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const idStr& a, + const char *b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const char *a, + const idStr& b + ) + + { + return !( a == b ); + } + +inline int idStr::icmpn + ( + const char *text, + int n + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::icmpn( m_data->data, text, n ); + } + +inline int idStr::icmpn + ( + const idStr& text, + int n + ) const + + { + assert( m_data ); + assert( text.m_data ); + + return idStr::icmpn( m_data->data, text.m_data->data, n ); + } + +inline int idStr::icmp + ( + const char *text + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::icmp( m_data->data, text ); + } + +inline int idStr::icmp + ( + const idStr& text + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::icmp( c_str () , text.c_str () ); + } + +inline int idStr::cmp + ( + const char *text + ) const + + { + assert( m_data ); + assert( text ); + + return idStr::cmp( m_data->data, text ); + } + +inline int idStr::cmp + ( + const idStr& text + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::cmp( c_str () , text.c_str () ); + } + +inline int idStr::cmpn + ( + const char *text, + int n + ) const + + { + assert( c_str () ); + assert( text ); + + return idStr::cmpn( c_str () , text, n ); + } + +inline int idStr::cmpn + ( + const idStr& text, + int n + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return idStr::cmpn( c_str () , text.c_str () , n ); + } + +inline void idStr::tolower + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + idStr::tolower( m_data->data ); + } + +inline void idStr::toupper + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + idStr::toupper( m_data->data ); + } + +inline bool idStr::isNumeric + ( + void + ) const + + { + assert( m_data ); + return idStr::isNumeric( m_data->data ); + } + +inline idStr::operator const char *() { + return c_str(); +} + +inline idStr::operator const char * + ( + void + ) const + + { + return c_str (); + } + +#endif diff --git a/libs/str.h b/libs/str.h index 8bb56ea9..8cb8a716 100644 --- a/libs/str.h +++ b/libs/str.h @@ -1,479 +1,479 @@ -/* -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 __STR__ -#define __STR__ - -// -// class Str -// loose replacement for CString from MFC -// - -#include <string.h> -#include <ctype.h> -#include <stdarg.h> - -#ifdef __APPLE__ - #ifdef NULL - #undef NULL - #define NULL 0 - #endif -#endif - - -#ifdef _WIN32 -#define strcasecmp strcmpi -#endif - -// NOTE TTimo __StrDup was initially implemented in pakstuff.cpp -// causing a bunch of issues for broader targets that use Str.h (such as plugins and modules) -// Q_StrDup should be used now, using a #define __StrDup for easy transition - -#define __StrDup Q_StrDup - -inline char* Q_StrDup(char* pStr) -{ - if (pStr == NULL) - pStr = ""; - - return strcpy(new char[strlen(pStr)+1], pStr); -} - -inline char* Q_StrDup(const char* pStr) -{ - if (pStr == NULL) - pStr = ""; - - return strcpy(new char[strlen(pStr)+1], pStr); -} - -#if defined (__linux__) || defined (__APPLE__) -#define strcmpi strcasecmp -#define stricmp strcasecmp -#define strnicmp strncasecmp - -inline char* strlwr(char* string) -{ - char *cp; - for (cp = string; *cp; ++cp) - { - if ('A' <= *cp && *cp <= 'Z') - *cp += 'a' - 'A'; - } - - return string; -} - -inline char* strupr(char* string) -{ - char *cp; - for (cp = string; *cp; ++cp) - { - if ('a' <= *cp && *cp <= 'z') - *cp += 'A' - 'a'; - } - - return string; -} -#endif - -static char *g_pStrWork = NULL; - -class Str -{ -protected: - bool m_bIgnoreCase; - char *m_pStr; - -public: - Str() - { - m_bIgnoreCase = true; - m_pStr = new char[1]; - m_pStr[0] = '\0'; - } - - Str(char *p) - { - m_bIgnoreCase = true; - m_pStr = __StrDup(p); - } - - Str(const char *p) - { - m_bIgnoreCase = true; - m_pStr = __StrDup(p); - } - - Str(const unsigned char *p) - { - m_bIgnoreCase = true; - m_pStr = __StrDup((const char *)p); - } - - Str(const char c) - { - m_bIgnoreCase = true; - m_pStr = new char[2]; - m_pStr[0] = c; - m_pStr[1] = '\0'; - } - - const char* GetBuffer() const - { - return m_pStr; - } - - Str(const Str &s) - { - m_bIgnoreCase = true; - m_pStr = __StrDup(s.GetBuffer()); - } - - void Deallocate() - { - delete []m_pStr; - m_pStr = NULL; - } - - void Allocate(int n) - { - Deallocate(); - m_pStr = new char[n]; - } - - void MakeEmpty() - { - Deallocate(); - m_pStr = __StrDup(""); - } - - virtual ~Str() - { - Deallocate(); - // NOTE TTimo: someone explain this g_pStrWork to me? - if (g_pStrWork) - delete []g_pStrWork; - g_pStrWork = NULL; - } - - void MakeLower() - { - if (m_pStr) - { - strlwr(m_pStr); - } - } - - void MakeUpper() - { - if (m_pStr) - { - strupr(m_pStr); - } - } - - void TrimRight() - { - char* lpsz = m_pStr; - char* lpszLast = NULL; - while (*lpsz != '\0') - { - if (isspace(*lpsz)) - { - if (lpszLast == NULL) - lpszLast = lpsz; - } - else - lpszLast = NULL; - lpsz++; - } - - if (lpszLast != NULL) - { - // truncate at trailing space start - *lpszLast = '\0'; - } - } - - void TrimLeft() - { - // find first non-space character - char* lpsz = m_pStr; - while (isspace(*lpsz)) - lpsz++; - - // fix up data and length - int nDataLength = GetLength() - (lpsz - m_pStr); - memmove(m_pStr, lpsz, (nDataLength+1)); - } - - int Find(const char *p) - { - char *pf = strstr(m_pStr, p); - return (pf) ? (pf - m_pStr) : -1; - } - - // search starting at a given offset - int Find(const char *p, int offset) - { - char *pf = strstr(m_pStr+offset, p); - return (pf) ? (pf - m_pStr) : -1; - } - - int Find(const char ch) - { - char *pf = strchr (m_pStr, ch); - return (pf) ? (pf - m_pStr) : -1; - } - - int ReverseFind(const char ch) - { - char *pf = strrchr(m_pStr, ch); - return (pf) ? (pf - m_pStr) : -1; - } - - int Compare (const char* str) const - { - return strcmp (m_pStr, str); - } - - int CompareNoCase (const char* str) const - { - return strcasecmp (m_pStr, str); - } - - int GetLength() - { - return (m_pStr) ? strlen(m_pStr) : 0; - } - - const char* Left(int n) - { - delete []g_pStrWork; - if (n > 0) - { - g_pStrWork = new char[n+1]; - strncpy(g_pStrWork, m_pStr, n); - g_pStrWork[n] = '\0'; - } - else - { - g_pStrWork = ""; - g_pStrWork = new char[1]; - g_pStrWork[0] = '\0'; - } - return g_pStrWork; - } - - const char* Right(int n) - { - delete []g_pStrWork; - if (n > 0) - { - g_pStrWork = new char[n+1]; - int nStart = GetLength() - n; - strncpy(g_pStrWork, &m_pStr[nStart], n); - g_pStrWork[n] = '\0'; - } - else - { - g_pStrWork = new char[1]; - g_pStrWork[0] = '\0'; - } - return g_pStrWork; - } - - const char* Mid(int nFirst) const - { - return Mid(nFirst, strlen (m_pStr) - nFirst); - } - - const char* Mid(int first, int n) const - { - delete []g_pStrWork; - if (n > 0) - { - g_pStrWork = new char[n+1]; - strncpy(g_pStrWork, m_pStr+first, n); - g_pStrWork[n] = '\0'; - } - else - { - g_pStrWork = ""; - g_pStrWork = new char[1]; - g_pStrWork[0] = '\0'; - } - return g_pStrWork; - } - -#ifdef __G_LIB_H__ - void Format(const char* fmt, ...) - { - va_list args; - char *buffer; - - va_start (args, fmt); - buffer = g_strdup_vprintf (fmt, args); - va_end (args); - - delete[] m_pStr; - m_pStr = __StrDup(buffer); - g_free (buffer); - } -#else - void Format(const char* fmt, ...) - { - va_list args; - m_pStr = new char[1024]; - - va_start (args, fmt); - vsprintf (m_pStr, fmt, args); - va_end (args); - } -#endif - - void SetAt(int n, char ch) - { - if (n >= 0 && n < GetLength ()) - m_pStr[n] = ch; - } - - // NOTE: unlike CString, this looses the pointer - void ReleaseBuffer(int n = -1) - { - if (n == -1) - n = GetLength (); - - char* tmp = m_pStr; - tmp[n] = '\0'; - m_pStr = __StrDup(tmp); - delete []tmp; - } - - char* GetBufferSetLength(int n) - { - if (n < 0) - n = 0; - - char *p = new char[n+1]; - strncpy (p, m_pStr, n); - p[n] = '\0'; - delete []m_pStr; - m_pStr = p; - return m_pStr; - } - - // char& operator *() { return *m_pStr; } - // char& operator *() const { return *const_cast<Str*>(this)->m_pStr; } - operator void*() { return m_pStr; } - operator char*() { return m_pStr; } - operator const char*(){ return reinterpret_cast<const char*>(m_pStr); } - operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); } - operator const unsigned char*() { return reinterpret_cast<const unsigned char*>(m_pStr); } - Str& operator =(const Str& rhs) - { - if (&rhs != this) - { - delete[] m_pStr; - m_pStr = __StrDup(rhs.m_pStr); - } - return *this; - } - - Str& operator =(const char* pStr) - { - if (m_pStr != pStr) - { - delete[] m_pStr; - m_pStr = __StrDup(pStr); - } - return *this; - } - - Str& operator +=(const char ch) - { - int len = GetLength (); - char *p = new char[len + 1 + 1]; - - if (m_pStr) - { - strcpy(p, m_pStr); - delete[] m_pStr; - } - - m_pStr = p; - m_pStr[len] = ch; - m_pStr[len+1] = '\0'; - - return *this; - } - - Str& operator +=(const char *pStr) - { - if (pStr) - { - if (m_pStr) - { - char *p = new char[strlen(m_pStr) + strlen(pStr) + 1]; - strcpy(p, m_pStr); - strcat(p, pStr); - delete[] m_pStr; - m_pStr = p; - } - else - { - m_pStr = __StrDup(pStr); - } - } - return *this; - } - - - bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; } - bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; } - bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; } - bool operator !=(Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) != 0 : strcmp(m_pStr, rhs.m_pStr) != 0; } - bool operator !=(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; } - bool operator !=(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; } - bool operator <(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) < 0 : strcmp(m_pStr, rhs.m_pStr) < 0; } - bool operator <(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; } - bool operator <(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; } - bool operator >(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) > 0 : strcmp(m_pStr, rhs.m_pStr) > 0; } - bool operator >(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; } - bool operator >(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; } - char& operator [](int nIndex) { return m_pStr[nIndex]; } - char& operator [](int nIndex) const { return m_pStr[nIndex]; } - const char GetAt (int nIndex) { return m_pStr[nIndex]; } -}; - - - -#endif +/* +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 __STR__ +#define __STR__ + +// +// class Str +// loose replacement for CString from MFC +// + +#include <string.h> +#include <ctype.h> +#include <stdarg.h> + +#ifdef __APPLE__ + #ifdef NULL + #undef NULL + #define NULL 0 + #endif +#endif + + +#ifdef _WIN32 +#define strcasecmp strcmpi +#endif + +// NOTE TTimo __StrDup was initially implemented in pakstuff.cpp +// causing a bunch of issues for broader targets that use Str.h (such as plugins and modules) +// Q_StrDup should be used now, using a #define __StrDup for easy transition + +#define __StrDup Q_StrDup + +inline char* Q_StrDup(char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} + +inline char* Q_StrDup(const char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} + +#if defined (__linux__) || defined (__APPLE__) +#define strcmpi strcasecmp +#define stricmp strcasecmp +#define strnicmp strncasecmp + +inline char* strlwr(char* string) +{ + char *cp; + for (cp = string; *cp; ++cp) + { + if ('A' <= *cp && *cp <= 'Z') + *cp += 'a' - 'A'; + } + + return string; +} + +inline char* strupr(char* string) +{ + char *cp; + for (cp = string; *cp; ++cp) + { + if ('a' <= *cp && *cp <= 'z') + *cp += 'A' - 'a'; + } + + return string; +} +#endif + +static char *g_pStrWork = NULL; + +class Str +{ +protected: + bool m_bIgnoreCase; + char *m_pStr; + +public: + Str() + { + m_bIgnoreCase = true; + m_pStr = new char[1]; + m_pStr[0] = '\0'; + } + + Str(char *p) + { + m_bIgnoreCase = true; + m_pStr = __StrDup(p); + } + + Str(const char *p) + { + m_bIgnoreCase = true; + m_pStr = __StrDup(p); + } + + Str(const unsigned char *p) + { + m_bIgnoreCase = true; + m_pStr = __StrDup((const char *)p); + } + + Str(const char c) + { + m_bIgnoreCase = true; + m_pStr = new char[2]; + m_pStr[0] = c; + m_pStr[1] = '\0'; + } + + const char* GetBuffer() const + { + return m_pStr; + } + + Str(const Str &s) + { + m_bIgnoreCase = true; + m_pStr = __StrDup(s.GetBuffer()); + } + + void Deallocate() + { + delete []m_pStr; + m_pStr = NULL; + } + + void Allocate(int n) + { + Deallocate(); + m_pStr = new char[n]; + } + + void MakeEmpty() + { + Deallocate(); + m_pStr = __StrDup(""); + } + + virtual ~Str() + { + Deallocate(); + // NOTE TTimo: someone explain this g_pStrWork to me? + if (g_pStrWork) + delete []g_pStrWork; + g_pStrWork = NULL; + } + + void MakeLower() + { + if (m_pStr) + { + strlwr(m_pStr); + } + } + + void MakeUpper() + { + if (m_pStr) + { + strupr(m_pStr); + } + } + + void TrimRight() + { + char* lpsz = m_pStr; + char* lpszLast = NULL; + while (*lpsz != '\0') + { + if (isspace(*lpsz)) + { + if (lpszLast == NULL) + lpszLast = lpsz; + } + else + lpszLast = NULL; + lpsz++; + } + + if (lpszLast != NULL) + { + // truncate at trailing space start + *lpszLast = '\0'; + } + } + + void TrimLeft() + { + // find first non-space character + char* lpsz = m_pStr; + while (isspace(*lpsz)) + lpsz++; + + // fix up data and length + int nDataLength = GetLength() - (lpsz - m_pStr); + memmove(m_pStr, lpsz, (nDataLength+1)); + } + + int Find(const char *p) + { + char *pf = strstr(m_pStr, p); + return (pf) ? (pf - m_pStr) : -1; + } + + // search starting at a given offset + int Find(const char *p, int offset) + { + char *pf = strstr(m_pStr+offset, p); + return (pf) ? (pf - m_pStr) : -1; + } + + int Find(const char ch) + { + char *pf = strchr (m_pStr, ch); + return (pf) ? (pf - m_pStr) : -1; + } + + int ReverseFind(const char ch) + { + char *pf = strrchr(m_pStr, ch); + return (pf) ? (pf - m_pStr) : -1; + } + + int Compare (const char* str) const + { + return strcmp (m_pStr, str); + } + + int CompareNoCase (const char* str) const + { + return strcasecmp (m_pStr, str); + } + + int GetLength() + { + return (m_pStr) ? strlen(m_pStr) : 0; + } + + const char* Left(int n) + { + delete []g_pStrWork; + if (n > 0) + { + g_pStrWork = new char[n+1]; + strncpy(g_pStrWork, m_pStr, n); + g_pStrWork[n] = '\0'; + } + else + { + g_pStrWork = ""; + g_pStrWork = new char[1]; + g_pStrWork[0] = '\0'; + } + return g_pStrWork; + } + + const char* Right(int n) + { + delete []g_pStrWork; + if (n > 0) + { + g_pStrWork = new char[n+1]; + int nStart = GetLength() - n; + strncpy(g_pStrWork, &m_pStr[nStart], n); + g_pStrWork[n] = '\0'; + } + else + { + g_pStrWork = new char[1]; + g_pStrWork[0] = '\0'; + } + return g_pStrWork; + } + + const char* Mid(int nFirst) const + { + return Mid(nFirst, strlen (m_pStr) - nFirst); + } + + const char* Mid(int first, int n) const + { + delete []g_pStrWork; + if (n > 0) + { + g_pStrWork = new char[n+1]; + strncpy(g_pStrWork, m_pStr+first, n); + g_pStrWork[n] = '\0'; + } + else + { + g_pStrWork = ""; + g_pStrWork = new char[1]; + g_pStrWork[0] = '\0'; + } + return g_pStrWork; + } + +#ifdef __G_LIB_H__ + void Format(const char* fmt, ...) + { + va_list args; + char *buffer; + + va_start (args, fmt); + buffer = g_strdup_vprintf (fmt, args); + va_end (args); + + delete[] m_pStr; + m_pStr = __StrDup(buffer); + g_free (buffer); + } +#else + void Format(const char* fmt, ...) + { + va_list args; + m_pStr = new char[1024]; + + va_start (args, fmt); + vsprintf (m_pStr, fmt, args); + va_end (args); + } +#endif + + void SetAt(int n, char ch) + { + if (n >= 0 && n < GetLength ()) + m_pStr[n] = ch; + } + + // NOTE: unlike CString, this looses the pointer + void ReleaseBuffer(int n = -1) + { + if (n == -1) + n = GetLength (); + + char* tmp = m_pStr; + tmp[n] = '\0'; + m_pStr = __StrDup(tmp); + delete []tmp; + } + + char* GetBufferSetLength(int n) + { + if (n < 0) + n = 0; + + char *p = new char[n+1]; + strncpy (p, m_pStr, n); + p[n] = '\0'; + delete []m_pStr; + m_pStr = p; + return m_pStr; + } + + // char& operator *() { return *m_pStr; } + // char& operator *() const { return *const_cast<Str*>(this)->m_pStr; } + operator void*() { return m_pStr; } + operator char*() { return m_pStr; } + operator const char*(){ return reinterpret_cast<const char*>(m_pStr); } + operator unsigned char*() { return reinterpret_cast<unsigned char*>(m_pStr); } + operator const unsigned char*() { return reinterpret_cast<const unsigned char*>(m_pStr); } + Str& operator =(const Str& rhs) + { + if (&rhs != this) + { + delete[] m_pStr; + m_pStr = __StrDup(rhs.m_pStr); + } + return *this; + } + + Str& operator =(const char* pStr) + { + if (m_pStr != pStr) + { + delete[] m_pStr; + m_pStr = __StrDup(pStr); + } + return *this; + } + + Str& operator +=(const char ch) + { + int len = GetLength (); + char *p = new char[len + 1 + 1]; + + if (m_pStr) + { + strcpy(p, m_pStr); + delete[] m_pStr; + } + + m_pStr = p; + m_pStr[len] = ch; + m_pStr[len+1] = '\0'; + + return *this; + } + + Str& operator +=(const char *pStr) + { + if (pStr) + { + if (m_pStr) + { + char *p = new char[strlen(m_pStr) + strlen(pStr) + 1]; + strcpy(p, m_pStr); + strcat(p, pStr); + delete[] m_pStr; + m_pStr = p; + } + else + { + m_pStr = __StrDup(pStr); + } + } + return *this; + } + + + bool operator ==(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) == 0 : strcmp(m_pStr, rhs.m_pStr) == 0; } + bool operator ==(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; } + bool operator ==(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) == 0 : strcmp(m_pStr, pStr) == 0; } + bool operator !=(Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) != 0 : strcmp(m_pStr, rhs.m_pStr) != 0; } + bool operator !=(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; } + bool operator !=(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) != 0 : strcmp(m_pStr, pStr) != 0; } + bool operator <(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) < 0 : strcmp(m_pStr, rhs.m_pStr) < 0; } + bool operator <(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; } + bool operator <(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) < 0 : strcmp(m_pStr, pStr) < 0; } + bool operator >(const Str& rhs) const { return (m_bIgnoreCase) ? stricmp(m_pStr, rhs.m_pStr) > 0 : strcmp(m_pStr, rhs.m_pStr) > 0; } + bool operator >(char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; } + bool operator >(const char* pStr) const { return (m_bIgnoreCase) ? stricmp(m_pStr, pStr) > 0 : strcmp(m_pStr, pStr) > 0; } + char& operator [](int nIndex) { return m_pStr[nIndex]; } + char& operator [](int nIndex) const { return m_pStr[nIndex]; } + const char GetAt (int nIndex) { return m_pStr[nIndex]; } +}; + + + +#endif diff --git a/libs/synapse.h b/libs/synapse.h index b01688fc..0478eb95 100644 --- a/libs/synapse.h +++ b/libs/synapse.h @@ -1,661 +1,661 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 __SYNAPSE_H__ -#define __SYNAPSE_H__ - -/*! -synapse library -code and utilities to deal with dynamic components programming - -"the point at which a nervous impulse passes from one neuron to another" - -dependencies: - libxml for parsing - STL for some algorithms and data structures - glib for Str.h (Str class) - -this is a utility library, it provides typical synapse client and server -could be split into two independant libraries actually, the server part and the client part -(that's just a matter of reducing binary size) -*/ - -// compile time settings -#ifdef _DEBUG - #define SYNAPSE_VERBOSE // be verbosive about the loading process -#endif - -// ydnar: required for os x -#if defined (__APPLE__) - #include <sys/types.h> -#endif - -#if defined (__linux__) || defined (__APPLE__) - #include <dlfcn.h> - #include <dirent.h> -#endif - -#if defined(_WIN32) - #include <windows.h> -#endif - -#if defined(_WIN32) - #define SYNAPSE_DLL_EXPORT WINAPI -#elif defined(__linux__) || defined(__APPLE__) /* ydnar */ -// #define SYNAPSE_DLL_EXPORT __attribute__ ((visibility ("protected"))) - #define SYNAPSE_DLL_EXPORT -#else - #error unknown architecture -#endif - -// NOTE TTimo: VC6 crap, gets confused when some variable names in function declarations -// are 'allocator' or 'list' -// if you #include glib *after* STL, you get those errors .. better be safe then -#include <glib.h> - -#include "libxml/parser.h" - -#include "irefcount.h" -#include "gtkr_list.h" -#include "gtkr_vector.h" - -#include "str.h" - -/*! -use when API change make things incompatible at synapse level -i.e. entry point and classes API changes -*/ -#define SYNAPSE_VERSION "3" - -/*! -======================================================================= -diagnostic printing facility -independently from any API negociation stuff, -we need a diagnostic facility that's available at all times -======================================================================= -*/ -extern "C" -{ -/*! -prototype to provide to synapse to redirect the output appropriately -*/ -typedef void (* PFN_SYN_PRINTF_VA) (const char *text, va_list args); -void Set_Syn_Printf(PFN_SYN_PRINTF_VA pf); ///< change the handler, set back to NULL for default -/*! -use this for synapse code diagnostics, it will be piped through the handler if necessary -*/ -void Syn_Printf (const char *text, ...); -}; - -/* -======================================================================= -client -======================================================================= -*/ - -/*! -description of an API: -a module requires and provides several APIs -the basic rule is that we will avoid asking an API from a module if the APIs it requires are not filled in yet -the exception being the 'resolve' operation of a given client, which we 'activate' -(that is we make the interfaces it provides available, leave the ones it requires unsolved, and try to get back to a stable situation) -*/ - -typedef enum { SYN_UNKNOWN = 0, SYN_PROVIDE, SYN_REQUIRE, SYN_REQUIRE_ANY } EAPIType; - -#define MAX_APINAME 128 -typedef struct APIDescriptor_s -{ - /*! - major version, this must be UNIQUE for each API - NOTE: we used to rely on GUID for this, that was a good solution to make sure we never get conflicts - but it was a bit overkill, so we dropped and use a string now - */ - char major_name[MAX_APINAME]; - /*! - what kind of interface - for instance for "image" API, "tga" "jpg" etc. - */ - char minor_name[MAX_APINAME]; - EAPIType mType; ///< is this an API we provide or an API we require - /*! - pointer to the table to be filled in - this is valid for SYN_REQUIRE APIs only - */ - void *mpTable; - bool mbTableInitDone; ///< turned to true by the server after the function table has been filled in - /*! - gives the size of the expected function table - */ - int mSize; - /*! - refcounts how many times this API is being used through the app - this is valid for SYN_PROVIDE APIs only - */ - int mRefCount; -} APIDescriptor_t; - -typedef struct XMLConfigEntry_s { - const char *api; - EAPIType type; - int size; - void *pTable; -} XMLConfigEntry_t; - -/*! -\class CSynapseAPIManager -derive from this class if you want to manage several APIs through the same object -(typically, loading plugins, or an unknown number of APIs that match some criterions) -this class has some pure virtual members that need to be implemented by the childs - -we deal with two types of API managers: -- the 'loose' ones have a matching pattern and load everything that matches criterions - typically used for plugins -- the 'list' ones have a fixed list of things they require. They are used to provide - easy access to multiple interfaces - -those two types of managers are not stored in the same structs, and not handled the -same way. For instance the 'list' manager will require ALL it's APIs to be loaded, or -the init will fail. They also play a role in the client activation. - -apart from the multiple API management facility, the main difference with static tables -and individual calls to CSynapseClient::AddAPI is the fact that the APIDescriptor_t are -allocated on demand -*/ - -/* we do some matching, or store minors list, the strings need to be bigger */ -#define MAX_PATTERN_STRING 512 - -/*! \enum EAPIManagerType - \brief type of this manager, loosely matching with "*", or a fixed list of required interfaces -*/ -typedef enum { API_MATCH = 0, API_LIST } EAPIManagerType; - -class CSynapseAPIManager : public IRefCounted -{ - EAPIManagerType mType; - - // the list of APIs we have obtained (SYN_REQUIRE_ANY) - vector< APIDescriptor_t * > mAPIs; - /*! - pattern for matching the major version - NOTE: only supported for now: exact match - */ - char major_pattern[MAX_PATTERN_STRING]; - /*! - pattern for matching the minor - */ - char minor_pattern[MAX_PATTERN_STRING]; - -public: - CSynapseAPIManager() { mType = API_MATCH; } - virtual ~CSynapseAPIManager(); - - EAPIManagerType GetType() { return mType; } - void SetType(EAPIManagerType type) { mType = type; } - - /*! - set the API matching pattern - supported syntax: - any minor for a given major, for instance: PLUGIN_MAJOR, "*" - a space seperated list of minors for a given major: IMAGE_MAJOR, "tga jpg" - */ - void SetMatchAPI(const char *major, const char *minor); - - /*! - utility function - start building a SYN_REQUIRE_ANY descriptor from a SYN_PROVIDE interface that we found matching - */ - static APIDescriptor_t* PrepareRequireAPI(APIDescriptor_t *pAPI); - - /*! - for managers that require a fixed list of things, we are not active until everything has been loaded up - managers that work on a loose pattern like "*" are always active (since they don't know what they want for sure) - */ - bool CheckSetActive(); - - /*! - the manager answers wether it wants to load this or not - we provide a default implementation, but this can be completely overriden if needed - see SetMatchAPI for the documentation of the default implementation - NOTE: this should only be called on API_MATCH type of managers - */ - virtual bool MatchAPI(const char *major, const char *minor); - - /*! - build an APIDescriptor_t configured as SYN_REQUIRE_ANY from the SYN_PROVIDE API we found - used when we scan the available interfaces for a match that would be interesting to this manager - NOTE: only for API_MATCH managers - */ - virtual APIDescriptor_t *BuildRequireAPI(APIDescriptor_t *pAPI) { return NULL; } - - /*! - below is relevant to API_LIST only --------------------------------------------------------------------- - */ - - /*! - fill in the table info to this descriptor, store it as a new slot - NOTE: only for API_LIST - */ - virtual void FillAPITable(APIDescriptor_t *pAPI) { } - - /*! - initialize the list of APIDescriptor_t* with all the stuff we expect - */ - void InitializeAPIList(); - - /*! - access the API descriptors - */ - int GetAPICount(); - APIDescriptor_t *GetAPI(int); -}; - -/*! -\class CSynapseClient -*/ -class CSynapseServer; // forward declare -class CSynapseClient : public IRefCounted -{ - /*! - this flag indicates wether this client is active - i.e. wether you can ask it for interfaces - this is either a client for which all required interfaces have been filled in - or a client we are trying to resolve (i.e. load with all it's stuff) - */ - bool mbActive; - - /*! - we store APIDescriptor_t*, the module fills that in at startup - */ - vector<APIDescriptor_t *> mAPIDescriptors; - - /*! - managers for multiple APIs management - mManagersMatch are managers with loose matching / undefined number of APIs - mManagersList are managers with a fixed list of required interfaces - */ - vector<CSynapseAPIManager *> mManagersMatch; - vector<CSynapseAPIManager *> mManagersList; - -protected: - friend class CSynapseServer; - /*! - use of this is restricted to the server, expecting it knows what it is doing - will make the client we are trying to resolve able to provide interfaces even though all interfaces it requires have not been filled in yet. - */ - void ForceSetActive() { mbActive = true; } - -public: - CSynapseClient(); - virtual ~CSynapseClient(); - - int GetAPICount(); ///< returns the number of APIs that this module provides - APIDescriptor_t* GetAPIDescriptor(int); ///< retrieve specific information about on of the APIs - - /*! - Add the API to the CSynapseClient information - - \param minor - minor can be NULL, some APIs don't need to have a 'minor' description - - \param type - SYN_PROVIDE: means this is an API we provide if anyone needs it - SYN_REQUIRE: means this is an API we will require for operation - SYN_REQUIRE_ANY: means this is an API we want to load *any* minor found - (for instance a list of image fornats, or the plugins) - - \param pTable - the function table - only valid for SYN_REQUIRE APIs - - \param size - the size of the function table - if SYN_REQUIRE, you should set the size in pTable and AddAPI will work it out - if SYN_PROVIDE, you need to provide this parameter - - returns a bool: - operation may fail, since we have a few safe checks - */ - bool AddAPI(const char *major, const char *minor = NULL, int size = 0, EAPIType type = SYN_PROVIDE, void *pTable = NULL); - - /*! - Add an API manager to the client - this class is designed to handle multiple APIs - is not memory managed by CSynapseClient (should it? or ref counted maybe?) - writing it with support for multiple managers, that may be a bit overkill right now - */ - void AddManager(CSynapseAPIManager *pManager); - - int GetManagerMatchCount(); ///< how many API managers - CSynapseAPIManager* GetManagerMatch(int); ///< get corresponding API manager - - int GetManagerListCount(); ///< how many API managers - CSynapseAPIManager* GetManagerList(int); ///< get corresponding API manager - - /*! - each client has to implement this function itself - it will fill in the function table - and increment the ref counting in it's own SYN_PROVIDE descriptor - returns a bool, false if you ask for an API that's not available - */ - virtual bool RequestAPI(APIDescriptor_t *pAPI) = 0; - - /*! - return the build date, can be overriden by client module - */ - virtual const char* GetInfo(); - - /*! - \brief a shirt name to identify the client - we use this string to identify individual clients, for instance when some XML configuration nodes are required - should be unique, the synapse server should't accept multiple occurences? - */ - virtual const char* GetName() { return ""; } - - bool IsActive() { return mbActive; } - /*! - check wether all interfaces have been filled in - in which case we will switch to 'activated' state, that is this client can provide interfaces to others now - */ - bool CheckSetActive(); - - /*! - \brief called when the client is being shutdown, before the dlclose happens - this is the last call before the dlclose, there's no turning back - just do what you have to do before you die.. decref and stuff - */ - void Shutdown(); - - /*! - override this one in clients that need to proceed through some init steps when activated - if returning false, the init will abort - */ - virtual bool OnActivate() { return true; } - - /*! - \brief walk the XML config and initialize from structures - when you use this function, OnActivate will also make sure all the interfaces listed were properly initialized - two tables, one for the regular single interface, one for the listings - need to store for later and check in OnActivate - - \param pServer, pass the server to talk to - NOTE: might want to store it in the class if that's needed too often - - \param client_name, the name of the client node to look for. If NULL, use GetName() - - \return wether all APIs given were successfully found in the config - */ - bool ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ); -}; - -/*! -prototype for the only exported function needed in a synapse client -*/ -#define NAME_SYNAPSE_ENUMERATEINTERFACES "Synapse_EnumerateInterfaces" - -class CSynapseServer; // forward declare -typedef CSynapseClient* (SYNAPSE_DLL_EXPORT *PFN_SYNAPSE_ENUMERATEINTERFACES)(const char *version, CSynapseServer *server); - -/*! -a derived version of CSynapseClient that can be used to provide builtin module without having to go through DLLs -this is useful for things we want to isolate behind an abstract API, but that we feel better about having present at all times (such as .def class loader) -*/ -class CSynapseBuiltinClient : public CSynapseClient -{ - public: - CSynapseBuiltinClient() {} - virtual ~CSynapseBuiltinClient() {} - - virtual void EnumerateInterfaces(CSynapseServer *server) = 0; - -}; - -/* -======================================================================= -server -======================================================================= -*/ - -/*! - \enum EClientType - \brief we can have clients that are builtin to a server -*/ -typedef enum { SYN_SO, SYN_BUILTIN } EClientType; - -/*! -server side slot for a synapse client -is OS dependant, except for the ISynapseClient part -*/ -class CSynapseClientSlot -{ -public: - /*! - \todo cleanup, make that private with accessors - */ -#if defined(__linux__) || defined(__APPLE__) - void *mpDLL; ///< handle to the shared object (invalid if SYN_BUILTIN) -#elif defined(_WIN32) - HMODULE mpDLL; ///< handle to the shared object (invalid if SYN_BUILTIN) -#endif - PFN_SYNAPSE_ENUMERATEINTERFACES mpEnumerate; ///< function pointer to the enumeration entry point (invalid if SYN_BUILTIN) - - CSynapseClient *mpClient; ///< the full client API - Str mFileName; ///< path to the file - - EClientType mType; - - /*! - \brief release the shared object. NOTE: OS dependent - */ - void ReleaseSO(); - - CSynapseClientSlot() { mpDLL = NULL; mpEnumerate = NULL; mpClient = NULL; mType = SYN_SO; } - /*! - NOTE: the slot is stored as static object, and copy constructors used - */ - virtual ~CSynapseClientSlot() { } - -}; - -/*! -\class CSynapseServer -dynamic modules manager class -this class provides the server functionality: -initialize, get a list of modules, load them, link them together.. -*/ -class CSynapseServer : public IRefCounted -{ - list<char *> mSearchPaths; - list<CSynapseClientSlot> mClients; - - /*! - used for resolve operations - */ - list<APIDescriptor_t*> mStack; - /*! - set this when mStack is modified with new stuff to resolve - NOTE: if this hack becomes too tricky to use we could just encapsulate mStack - */ - bool mbStackChanged; - - xmlDocPtr mpDoc; - xmlNodePtr mpFocusedNode; ///< currently focused node while we are scanning the config (strictly for GetNextConfig usage) - xmlNodePtr mpCurrentClientConfig; - /*! - stores the allocated strings for each call to GetNextConfig - need to be freed if != NULL - */ - xmlChar *m_api_name; - gchar *m_content; - - /*! - push required interfaces for this client into the stack of things to be resolved - it is possible that several mathing interfaces be in the stack at the same time - (for instance several modules that want to get the VFS) - but we should never have the same APIDescriptor_t twice - NOTE: as this function is called repeatedly during the resolve (because the list of required things is refining), - we often have to drop APIDescriptor_t requests that are already there. - NOTE CSynapseAPIManager: if there are CSynapseAPIManager objects in the CSynapseClient, - we will scan and push all the matching APIs too - */ - void PushRequired(CSynapseClient *pClient); - - /*! - work on resolving this particular APIDescriptor_t - returns true if we were able to resolve the interface - returns false otherwise - if the API was found, but not requested because of more required APIs, we push them in mStack - */ - bool ResolveAPI(APIDescriptor_t* pAPI); - - /*! - push an APIDescriptor_t* into the stack of things to be resolved - will check that this is not already present first - will update the mbStackChanged flag - */ - void TryPushStack(APIDescriptor_t *); - - /*! - \brief 'client shutdown' (see libs/synapse/docs/unload.txt) - performs a 'client shutdown' - will free the DLL module - before calling here, the client must be in a 'non active' state - (i.e. it was not used at all during startup, or we have properly done a 'release' already) - we scan the mStack for the SYN_REQUIRE that this client owns, and remove them - \param iSlot is an mClients iterator, invalid when the function returns as the item will have been removed from the list - \return the iterator afer erase call so that the caller iteration can continue - */ - list<CSynapseClientSlot>::iterator ShutdownClient(list<CSynapseClientSlot>::iterator iSlot); - - /*! - \brief actual implementation of the Resolve function - */ - bool DoResolve(CSynapseClient *pClient); - -public: - CSynapseServer(); - virtual ~CSynapseServer(); - - void AddSearchPath(char*); ///< add a new directory to the module search path - /*! - do the big thing, scan for modules, scan their APIs, load up everything - providing pf is optional, will set the diagnostics printing - \param conf_file is the XML configuration file for the intialization (see docs/runtime.txt) - \return false if the init failed (for instance not found/invalid conf file - */ - bool Initialize(const char* conf_file = NULL, PFN_SYN_PRINTF_VA pf = NULL); - - /*! - enumerate the interfaces for a given module - this will load it, query it's entry point, and request the APIs - */ - void EnumerateInterfaces(Str &); - - /*! - enumerate the interfaces for a module that is builtin to the server - */ - void EnumerateBuiltinModule(CSynapseBuiltinClient *); - - /*! - \brief resolve the function table loading for this client - if the client is not listed in the known slots yet, it will be added - wraps around internal DoResolve implementation to unload the unused modules - \return wether the resolution has been successful - */ - bool Resolve(CSynapseClient *pClient); - - /*! - \brief shutdown all the clients. Should only be called when the core is about to exit - this will force all clients to shutdown. it may destroy refcounted APIs and stuff - \todo hafta use the release/refresh code before doing actual shutdown - (i.e. when that code is written later on) - we need to 'broadcast' to all the clients .. that all the modules are going to be reloaded sorta - should clear up as many interfaces as possible to avoid unexpected crashes in the final stages of app exit - */ - void Shutdown(); - - /*! - diagnostic print function - NOTE: - it is essential that those functions should be virtual, - otherwise when accessing the g_pPrintf global we could mismatch - (happens because the same library is linked into server and client) - */ - virtual PFN_SYN_PRINTF_VA Get_Syn_Printf(); - - /*! - \return true if those APIs are matching - we provide two APIs for convenience, actual implementation is MatchAPI - the minors have to be both NULL, or equal, or one the minors be '*' - NOTE: the '*' minor should ONLY be used on an API that will be unique. It is hackish and kinda dangerous - */ - static bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ); - static bool MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ); - -#if defined(_WIN32) - /*! - utility function to retrieve formatted GetLastError message - ANSI text, static string - */ - static const char* FormatGetLastError(); -#endif - - /*! - dump the stack of interfaces to be solved - this is used when synapse initialization failed to quickly identify the missing/broken pieces - */ - void DumpStack(); - - /*! - general purpose information, list what modules are loaded up - */ - void DumpActiveClients(); - - /*! - \brief select the config node that has this name - call this to locate the right node in XML config - this will focus and get ready to walk through the api nodes - \return wether the config node was correctly selected - */ - bool SelectClientConfig(const char *client_name); - - /*! - \brief walk through the apis - the pointers don't need to be freed - you need to copy them over as they are invalidated between each call to GetNextConfig - \return false when all apis have been parsed - */ - bool GetNextConfig(char **api_name, char **minor); - - /*! - \brief read the minor for a given api in the current config - \return false if this node doesn't exist - */ - bool GetConfigForAPI( const char *api, char **minor ); - - /*! - returns the filename of the module that the passed on client exists in - */ - const char *GetModuleFilename(CSynapseClient *pClient); -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 __SYNAPSE_H__ +#define __SYNAPSE_H__ + +/*! +synapse library +code and utilities to deal with dynamic components programming + +"the point at which a nervous impulse passes from one neuron to another" + +dependencies: + libxml for parsing + STL for some algorithms and data structures + glib for Str.h (Str class) + +this is a utility library, it provides typical synapse client and server +could be split into two independant libraries actually, the server part and the client part +(that's just a matter of reducing binary size) +*/ + +// compile time settings +#ifdef _DEBUG + #define SYNAPSE_VERBOSE // be verbosive about the loading process +#endif + +// ydnar: required for os x +#if defined (__APPLE__) + #include <sys/types.h> +#endif + +#if defined (__linux__) || defined (__APPLE__) + #include <dlfcn.h> + #include <dirent.h> +#endif + +#if defined(_WIN32) + #include <windows.h> +#endif + +#if defined(_WIN32) + #define SYNAPSE_DLL_EXPORT WINAPI +#elif defined(__linux__) || defined(__APPLE__) /* ydnar */ +// #define SYNAPSE_DLL_EXPORT __attribute__ ((visibility ("protected"))) + #define SYNAPSE_DLL_EXPORT +#else + #error unknown architecture +#endif + +// NOTE TTimo: VC6 crap, gets confused when some variable names in function declarations +// are 'allocator' or 'list' +// if you #include glib *after* STL, you get those errors .. better be safe then +#include <glib.h> + +#include "libxml/parser.h" + +#include "irefcount.h" +#include "gtkr_list.h" +#include "gtkr_vector.h" + +#include "str.h" + +/*! +use when API change make things incompatible at synapse level +i.e. entry point and classes API changes +*/ +#define SYNAPSE_VERSION "3" + +/*! +======================================================================= +diagnostic printing facility +independently from any API negociation stuff, +we need a diagnostic facility that's available at all times +======================================================================= +*/ +extern "C" +{ +/*! +prototype to provide to synapse to redirect the output appropriately +*/ +typedef void (* PFN_SYN_PRINTF_VA) (const char *text, va_list args); +void Set_Syn_Printf(PFN_SYN_PRINTF_VA pf); ///< change the handler, set back to NULL for default +/*! +use this for synapse code diagnostics, it will be piped through the handler if necessary +*/ +void Syn_Printf (const char *text, ...); +}; + +/* +======================================================================= +client +======================================================================= +*/ + +/*! +description of an API: +a module requires and provides several APIs +the basic rule is that we will avoid asking an API from a module if the APIs it requires are not filled in yet +the exception being the 'resolve' operation of a given client, which we 'activate' +(that is we make the interfaces it provides available, leave the ones it requires unsolved, and try to get back to a stable situation) +*/ + +typedef enum { SYN_UNKNOWN = 0, SYN_PROVIDE, SYN_REQUIRE, SYN_REQUIRE_ANY } EAPIType; + +#define MAX_APINAME 128 +typedef struct APIDescriptor_s +{ + /*! + major version, this must be UNIQUE for each API + NOTE: we used to rely on GUID for this, that was a good solution to make sure we never get conflicts + but it was a bit overkill, so we dropped and use a string now + */ + char major_name[MAX_APINAME]; + /*! + what kind of interface + for instance for "image" API, "tga" "jpg" etc. + */ + char minor_name[MAX_APINAME]; + EAPIType mType; ///< is this an API we provide or an API we require + /*! + pointer to the table to be filled in + this is valid for SYN_REQUIRE APIs only + */ + void *mpTable; + bool mbTableInitDone; ///< turned to true by the server after the function table has been filled in + /*! + gives the size of the expected function table + */ + int mSize; + /*! + refcounts how many times this API is being used through the app + this is valid for SYN_PROVIDE APIs only + */ + int mRefCount; +} APIDescriptor_t; + +typedef struct XMLConfigEntry_s { + const char *api; + EAPIType type; + int size; + void *pTable; +} XMLConfigEntry_t; + +/*! +\class CSynapseAPIManager +derive from this class if you want to manage several APIs through the same object +(typically, loading plugins, or an unknown number of APIs that match some criterions) +this class has some pure virtual members that need to be implemented by the childs + +we deal with two types of API managers: +- the 'loose' ones have a matching pattern and load everything that matches criterions + typically used for plugins +- the 'list' ones have a fixed list of things they require. They are used to provide + easy access to multiple interfaces + +those two types of managers are not stored in the same structs, and not handled the +same way. For instance the 'list' manager will require ALL it's APIs to be loaded, or +the init will fail. They also play a role in the client activation. + +apart from the multiple API management facility, the main difference with static tables +and individual calls to CSynapseClient::AddAPI is the fact that the APIDescriptor_t are +allocated on demand +*/ + +/* we do some matching, or store minors list, the strings need to be bigger */ +#define MAX_PATTERN_STRING 512 + +/*! \enum EAPIManagerType + \brief type of this manager, loosely matching with "*", or a fixed list of required interfaces +*/ +typedef enum { API_MATCH = 0, API_LIST } EAPIManagerType; + +class CSynapseAPIManager : public IRefCounted +{ + EAPIManagerType mType; + + // the list of APIs we have obtained (SYN_REQUIRE_ANY) + vector< APIDescriptor_t * > mAPIs; + /*! + pattern for matching the major version + NOTE: only supported for now: exact match + */ + char major_pattern[MAX_PATTERN_STRING]; + /*! + pattern for matching the minor + */ + char minor_pattern[MAX_PATTERN_STRING]; + +public: + CSynapseAPIManager() { mType = API_MATCH; } + virtual ~CSynapseAPIManager(); + + EAPIManagerType GetType() { return mType; } + void SetType(EAPIManagerType type) { mType = type; } + + /*! + set the API matching pattern + supported syntax: + any minor for a given major, for instance: PLUGIN_MAJOR, "*" + a space seperated list of minors for a given major: IMAGE_MAJOR, "tga jpg" + */ + void SetMatchAPI(const char *major, const char *minor); + + /*! + utility function + start building a SYN_REQUIRE_ANY descriptor from a SYN_PROVIDE interface that we found matching + */ + static APIDescriptor_t* PrepareRequireAPI(APIDescriptor_t *pAPI); + + /*! + for managers that require a fixed list of things, we are not active until everything has been loaded up + managers that work on a loose pattern like "*" are always active (since they don't know what they want for sure) + */ + bool CheckSetActive(); + + /*! + the manager answers wether it wants to load this or not + we provide a default implementation, but this can be completely overriden if needed + see SetMatchAPI for the documentation of the default implementation + NOTE: this should only be called on API_MATCH type of managers + */ + virtual bool MatchAPI(const char *major, const char *minor); + + /*! + build an APIDescriptor_t configured as SYN_REQUIRE_ANY from the SYN_PROVIDE API we found + used when we scan the available interfaces for a match that would be interesting to this manager + NOTE: only for API_MATCH managers + */ + virtual APIDescriptor_t *BuildRequireAPI(APIDescriptor_t *pAPI) { return NULL; } + + /*! + below is relevant to API_LIST only --------------------------------------------------------------------- + */ + + /*! + fill in the table info to this descriptor, store it as a new slot + NOTE: only for API_LIST + */ + virtual void FillAPITable(APIDescriptor_t *pAPI) { } + + /*! + initialize the list of APIDescriptor_t* with all the stuff we expect + */ + void InitializeAPIList(); + + /*! + access the API descriptors + */ + int GetAPICount(); + APIDescriptor_t *GetAPI(int); +}; + +/*! +\class CSynapseClient +*/ +class CSynapseServer; // forward declare +class CSynapseClient : public IRefCounted +{ + /*! + this flag indicates wether this client is active + i.e. wether you can ask it for interfaces + this is either a client for which all required interfaces have been filled in + or a client we are trying to resolve (i.e. load with all it's stuff) + */ + bool mbActive; + + /*! + we store APIDescriptor_t*, the module fills that in at startup + */ + vector<APIDescriptor_t *> mAPIDescriptors; + + /*! + managers for multiple APIs management + mManagersMatch are managers with loose matching / undefined number of APIs + mManagersList are managers with a fixed list of required interfaces + */ + vector<CSynapseAPIManager *> mManagersMatch; + vector<CSynapseAPIManager *> mManagersList; + +protected: + friend class CSynapseServer; + /*! + use of this is restricted to the server, expecting it knows what it is doing + will make the client we are trying to resolve able to provide interfaces even though all interfaces it requires have not been filled in yet. + */ + void ForceSetActive() { mbActive = true; } + +public: + CSynapseClient(); + virtual ~CSynapseClient(); + + int GetAPICount(); ///< returns the number of APIs that this module provides + APIDescriptor_t* GetAPIDescriptor(int); ///< retrieve specific information about on of the APIs + + /*! + Add the API to the CSynapseClient information + + \param minor + minor can be NULL, some APIs don't need to have a 'minor' description + + \param type + SYN_PROVIDE: means this is an API we provide if anyone needs it + SYN_REQUIRE: means this is an API we will require for operation + SYN_REQUIRE_ANY: means this is an API we want to load *any* minor found + (for instance a list of image fornats, or the plugins) + + \param pTable + the function table + only valid for SYN_REQUIRE APIs + + \param size + the size of the function table + if SYN_REQUIRE, you should set the size in pTable and AddAPI will work it out + if SYN_PROVIDE, you need to provide this parameter + + returns a bool: + operation may fail, since we have a few safe checks + */ + bool AddAPI(const char *major, const char *minor = NULL, int size = 0, EAPIType type = SYN_PROVIDE, void *pTable = NULL); + + /*! + Add an API manager to the client + this class is designed to handle multiple APIs + is not memory managed by CSynapseClient (should it? or ref counted maybe?) + writing it with support for multiple managers, that may be a bit overkill right now + */ + void AddManager(CSynapseAPIManager *pManager); + + int GetManagerMatchCount(); ///< how many API managers + CSynapseAPIManager* GetManagerMatch(int); ///< get corresponding API manager + + int GetManagerListCount(); ///< how many API managers + CSynapseAPIManager* GetManagerList(int); ///< get corresponding API manager + + /*! + each client has to implement this function itself + it will fill in the function table + and increment the ref counting in it's own SYN_PROVIDE descriptor + returns a bool, false if you ask for an API that's not available + */ + virtual bool RequestAPI(APIDescriptor_t *pAPI) = 0; + + /*! + return the build date, can be overriden by client module + */ + virtual const char* GetInfo(); + + /*! + \brief a shirt name to identify the client + we use this string to identify individual clients, for instance when some XML configuration nodes are required + should be unique, the synapse server should't accept multiple occurences? + */ + virtual const char* GetName() { return ""; } + + bool IsActive() { return mbActive; } + /*! + check wether all interfaces have been filled in + in which case we will switch to 'activated' state, that is this client can provide interfaces to others now + */ + bool CheckSetActive(); + + /*! + \brief called when the client is being shutdown, before the dlclose happens + this is the last call before the dlclose, there's no turning back + just do what you have to do before you die.. decref and stuff + */ + void Shutdown(); + + /*! + override this one in clients that need to proceed through some init steps when activated + if returning false, the init will abort + */ + virtual bool OnActivate() { return true; } + + /*! + \brief walk the XML config and initialize from structures + when you use this function, OnActivate will also make sure all the interfaces listed were properly initialized + two tables, one for the regular single interface, one for the listings + need to store for later and check in OnActivate + + \param pServer, pass the server to talk to + NOTE: might want to store it in the class if that's needed too often + + \param client_name, the name of the client node to look for. If NULL, use GetName() + + \return wether all APIs given were successfully found in the config + */ + bool ConfigXML( CSynapseServer *pServer, const char *client_name, const XMLConfigEntry_t entries[] ); +}; + +/*! +prototype for the only exported function needed in a synapse client +*/ +#define NAME_SYNAPSE_ENUMERATEINTERFACES "Synapse_EnumerateInterfaces" + +class CSynapseServer; // forward declare +typedef CSynapseClient* (SYNAPSE_DLL_EXPORT *PFN_SYNAPSE_ENUMERATEINTERFACES)(const char *version, CSynapseServer *server); + +/*! +a derived version of CSynapseClient that can be used to provide builtin module without having to go through DLLs +this is useful for things we want to isolate behind an abstract API, but that we feel better about having present at all times (such as .def class loader) +*/ +class CSynapseBuiltinClient : public CSynapseClient +{ + public: + CSynapseBuiltinClient() {} + virtual ~CSynapseBuiltinClient() {} + + virtual void EnumerateInterfaces(CSynapseServer *server) = 0; + +}; + +/* +======================================================================= +server +======================================================================= +*/ + +/*! + \enum EClientType + \brief we can have clients that are builtin to a server +*/ +typedef enum { SYN_SO, SYN_BUILTIN } EClientType; + +/*! +server side slot for a synapse client +is OS dependant, except for the ISynapseClient part +*/ +class CSynapseClientSlot +{ +public: + /*! + \todo cleanup, make that private with accessors + */ +#if defined(__linux__) || defined(__APPLE__) + void *mpDLL; ///< handle to the shared object (invalid if SYN_BUILTIN) +#elif defined(_WIN32) + HMODULE mpDLL; ///< handle to the shared object (invalid if SYN_BUILTIN) +#endif + PFN_SYNAPSE_ENUMERATEINTERFACES mpEnumerate; ///< function pointer to the enumeration entry point (invalid if SYN_BUILTIN) + + CSynapseClient *mpClient; ///< the full client API + Str mFileName; ///< path to the file + + EClientType mType; + + /*! + \brief release the shared object. NOTE: OS dependent + */ + void ReleaseSO(); + + CSynapseClientSlot() { mpDLL = NULL; mpEnumerate = NULL; mpClient = NULL; mType = SYN_SO; } + /*! + NOTE: the slot is stored as static object, and copy constructors used + */ + virtual ~CSynapseClientSlot() { } + +}; + +/*! +\class CSynapseServer +dynamic modules manager class +this class provides the server functionality: +initialize, get a list of modules, load them, link them together.. +*/ +class CSynapseServer : public IRefCounted +{ + list<char *> mSearchPaths; + list<CSynapseClientSlot> mClients; + + /*! + used for resolve operations + */ + list<APIDescriptor_t*> mStack; + /*! + set this when mStack is modified with new stuff to resolve + NOTE: if this hack becomes too tricky to use we could just encapsulate mStack + */ + bool mbStackChanged; + + xmlDocPtr mpDoc; + xmlNodePtr mpFocusedNode; ///< currently focused node while we are scanning the config (strictly for GetNextConfig usage) + xmlNodePtr mpCurrentClientConfig; + /*! + stores the allocated strings for each call to GetNextConfig + need to be freed if != NULL + */ + xmlChar *m_api_name; + gchar *m_content; + + /*! + push required interfaces for this client into the stack of things to be resolved + it is possible that several mathing interfaces be in the stack at the same time + (for instance several modules that want to get the VFS) + but we should never have the same APIDescriptor_t twice + NOTE: as this function is called repeatedly during the resolve (because the list of required things is refining), + we often have to drop APIDescriptor_t requests that are already there. + NOTE CSynapseAPIManager: if there are CSynapseAPIManager objects in the CSynapseClient, + we will scan and push all the matching APIs too + */ + void PushRequired(CSynapseClient *pClient); + + /*! + work on resolving this particular APIDescriptor_t + returns true if we were able to resolve the interface + returns false otherwise + if the API was found, but not requested because of more required APIs, we push them in mStack + */ + bool ResolveAPI(APIDescriptor_t* pAPI); + + /*! + push an APIDescriptor_t* into the stack of things to be resolved + will check that this is not already present first + will update the mbStackChanged flag + */ + void TryPushStack(APIDescriptor_t *); + + /*! + \brief 'client shutdown' (see libs/synapse/docs/unload.txt) + performs a 'client shutdown' + will free the DLL module + before calling here, the client must be in a 'non active' state + (i.e. it was not used at all during startup, or we have properly done a 'release' already) + we scan the mStack for the SYN_REQUIRE that this client owns, and remove them + \param iSlot is an mClients iterator, invalid when the function returns as the item will have been removed from the list + \return the iterator afer erase call so that the caller iteration can continue + */ + list<CSynapseClientSlot>::iterator ShutdownClient(list<CSynapseClientSlot>::iterator iSlot); + + /*! + \brief actual implementation of the Resolve function + */ + bool DoResolve(CSynapseClient *pClient); + +public: + CSynapseServer(); + virtual ~CSynapseServer(); + + void AddSearchPath(char*); ///< add a new directory to the module search path + /*! + do the big thing, scan for modules, scan their APIs, load up everything + providing pf is optional, will set the diagnostics printing + \param conf_file is the XML configuration file for the intialization (see docs/runtime.txt) + \return false if the init failed (for instance not found/invalid conf file + */ + bool Initialize(const char* conf_file = NULL, PFN_SYN_PRINTF_VA pf = NULL); + + /*! + enumerate the interfaces for a given module + this will load it, query it's entry point, and request the APIs + */ + void EnumerateInterfaces(Str &); + + /*! + enumerate the interfaces for a module that is builtin to the server + */ + void EnumerateBuiltinModule(CSynapseBuiltinClient *); + + /*! + \brief resolve the function table loading for this client + if the client is not listed in the known slots yet, it will be added + wraps around internal DoResolve implementation to unload the unused modules + \return wether the resolution has been successful + */ + bool Resolve(CSynapseClient *pClient); + + /*! + \brief shutdown all the clients. Should only be called when the core is about to exit + this will force all clients to shutdown. it may destroy refcounted APIs and stuff + \todo hafta use the release/refresh code before doing actual shutdown + (i.e. when that code is written later on) + we need to 'broadcast' to all the clients .. that all the modules are going to be reloaded sorta + should clear up as many interfaces as possible to avoid unexpected crashes in the final stages of app exit + */ + void Shutdown(); + + /*! + diagnostic print function + NOTE: + it is essential that those functions should be virtual, + otherwise when accessing the g_pPrintf global we could mismatch + (happens because the same library is linked into server and client) + */ + virtual PFN_SYN_PRINTF_VA Get_Syn_Printf(); + + /*! + \return true if those APIs are matching + we provide two APIs for convenience, actual implementation is MatchAPI + the minors have to be both NULL, or equal, or one the minors be '*' + NOTE: the '*' minor should ONLY be used on an API that will be unique. It is hackish and kinda dangerous + */ + static bool MatchAPI( APIDescriptor_t *p1, APIDescriptor_t *p2 ); + static bool MatchAPI( const char* major1, const char* minor1, const char* major2, const char* minor2 ); + +#if defined(_WIN32) + /*! + utility function to retrieve formatted GetLastError message + ANSI text, static string + */ + static const char* FormatGetLastError(); +#endif + + /*! + dump the stack of interfaces to be solved + this is used when synapse initialization failed to quickly identify the missing/broken pieces + */ + void DumpStack(); + + /*! + general purpose information, list what modules are loaded up + */ + void DumpActiveClients(); + + /*! + \brief select the config node that has this name + call this to locate the right node in XML config + this will focus and get ready to walk through the api nodes + \return wether the config node was correctly selected + */ + bool SelectClientConfig(const char *client_name); + + /*! + \brief walk through the apis + the pointers don't need to be freed + you need to copy them over as they are invalidated between each call to GetNextConfig + \return false when all apis have been parsed + */ + bool GetNextConfig(char **api_name, char **minor); + + /*! + \brief read the minor for a given api in the current config + \return false if this node doesn't exist + */ + bool GetConfigForAPI( const char *api, char **minor ); + + /*! + returns the filename of the module that the passed on client exists in + */ + const char *GetModuleFilename(CSynapseClient *pClient); +}; + +#endif diff --git a/plugins/eclassfgd/plugin.h b/plugins/eclassfgd/plugin.h index 4b707f49..5f402c17 100644 --- a/plugins/eclassfgd/plugin.h +++ b/plugins/eclassfgd/plugin.h @@ -1,49 +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 _PLUGIN_H_ -#define _PLUGIN_H_ - -#include <stdlib.h> -#include <stdio.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 USE_VFSTABLE_DEFINE -#include "ifilesystem.h" - -class CSynapseClientFGD : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientFGD() { } - virtual ~CSynapseClientFGD() { } -}; - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> +#include <stdio.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 USE_VFSTABLE_DEFINE +#include "ifilesystem.h" + +class CSynapseClientFGD : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientFGD() { } + virtual ~CSynapseClientFGD() { } +}; + +#endif // _PLUGIN_H_ diff --git a/plugins/entity/entity.h b/plugins/entity/entity.h index 25a925d0..6ae14603 100644 --- a/plugins/entity/entity.h +++ b/plugins/entity/entity.h @@ -1,52 +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 -*/ - -// entity.h - -// external API - -// construct -entity_t* Entity_Alloc(); -// destruct -void Entity_Free (entity_t *e); -// construct from entity -entity_t* Entity_Clone (entity_t *e); - -// epair interface -void SetKeyValue (entity_t *ent, const char *key, const char *value); -void DeleteKey (entity_t *ent, const char *key); -const char* ValueForKey (entity_t *ent, const char *key); -float FloatForKey (entity_t *ent, const char *key); -int IntForKey (entity_t *ent, const char *key); -void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec); - -void Entity_AddToList(entity_t *e, entity_t *lst); -void Entity_RemoveFromList(entity_t *e); - -void Entity_LinkBrush (entity_t *e, brush_t *b); -void Entity_UnlinkBrush (brush_t *b); - -// for undo -int Entity_MemorySize(entity_t *e); - -epair_t* Entity_AllocateEpair(const char *key, const char *value); -epair_t** Entity_GetKeyValList(entity_t *e); -void Entity_SetKeyValList(entity_t *e, epair_t* ep); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// entity.h + +// external API + +// construct +entity_t* Entity_Alloc(); +// destruct +void Entity_Free (entity_t *e); +// construct from entity +entity_t* Entity_Clone (entity_t *e); + +// epair interface +void SetKeyValue (entity_t *ent, const char *key, const char *value); +void DeleteKey (entity_t *ent, const char *key); +const char* ValueForKey (entity_t *ent, const char *key); +float FloatForKey (entity_t *ent, const char *key); +int IntForKey (entity_t *ent, const char *key); +void GetVectorForKey (entity_t *ent, const char *key, vec3_t vec); + +void Entity_AddToList(entity_t *e, entity_t *lst); +void Entity_RemoveFromList(entity_t *e); + +void Entity_LinkBrush (entity_t *e, brush_t *b); +void Entity_UnlinkBrush (brush_t *b); + +// for undo +int Entity_MemorySize(entity_t *e); + +epair_t* Entity_AllocateEpair(const char *key, const char *value); +epair_t** Entity_GetKeyValList(entity_t *e); +void Entity_SetKeyValList(entity_t *e, epair_t* ep); diff --git a/plugins/entity/entity_entitymodel.h b/plugins/entity/entity_entitymodel.h index a805c219..dca34ae8 100644 --- a/plugins/entity/entity_entitymodel.h +++ b/plugins/entity/entity_entitymodel.h @@ -1,150 +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 _ENTITYMODEL_H_ -#define _ENTITYMODEL_H_ - -#include "plugin.h" - -/*! simulates misc_model entity behaviours for rendering/selection/editing */ -class CEntityMiscModel : public IRender, public ISelect, public IEdit -{ -public: - CEntityMiscModel (entity_t *e); - virtual ~CEntityMiscModel (); - - void IncRef() { refCount++; } - void DecRef() { if(--refCount == 0) delete this; } - - // IRender - void Draw(int state, int rflags) const; - const aabb_t *GetAABB() const { return &m_BBox; } - - // ISelect - bool TestRay(const ray_t *ray, vec_t *dist) const; - //bool TestBox(const aabb_t aabb) const; - - // ITransform - void Translate(const vec3_t translation); - void Rotate(const vec3_t pivot, const vec3_t rotation); - const vec_t *GetTranslation() const { return m_translate; } - const vec_t *GetRotation() const { return m_euler; } - void OnKeyValueChanged(entity_t *e, const char *key, const char* value); - - void SetName(const char *name); -private: - void BuildCacheRequestString(const char *name); - /*! updates the AABB and transformation matrix */ - void UpdateCachedData(); - entity_interfaces_t *m_model; - - entity_t *m_entity; - - int refCount; - string_t m_version; - - Str m_cachereq; - - /*! AABB in local space */ - aabb_t m_BBox; - - /*! worldspace-to-localspace translation */ - vec3_t m_translate; - - /*! worldspace-to-localspace euler rotation angles */ - vec3_t m_euler; - - /*! worldspace-to-localspace scale */ - vec3_t m_scale; - - /*! localspace origin, effectively rotation & scale pivot point */ - vec3_t m_pivot; - - /*! worldspace-to-localspace transform, generated from translate/euler/scale/pivot */ - m4x4_t m_transform; - - /*! localspace-to-worldspace transform */ - m4x4_t m_inverse_transform; -}; - -/*! simulates eclass-model entity behaviours for rendering/selection/editing */ -class CEntityEclassModel : public IRender, public ISelect, public IEdit -{ -public: - CEntityEclassModel (); - virtual ~CEntityEclassModel (); - - void IncRef() { refCount++; } - void DecRef() { if(--refCount == 0) delete this; } - - // IRender - void Draw(int state, int rflags) const; - const aabb_t *GetAABB() const { return &m_BBox; } - - // ISelect - bool TestRay(const ray_t *ray, vec_t *dist) const; - //bool TestBox(const aabb_t aabb) const; - - // ITransform - void Translate(const vec3_t translation); - void Rotate(const vec3_t pivot, const vec3_t rotation); - const vec_t *GetTranslation() const { return m_translate; } - const vec_t *GetRotation() const { return m_euler; } - void OnKeyValueChanged(entity_t *e, const char *key, const char* value); - - void SetName(const char *name); - void SetEclass(const eclass_t* eclass); -private: - /*! updates the AABB and transformation matrix */ - void UpdateCachedData(); - entity_interfaces_t *m_model; - - int refCount; - string_t m_name; - string_t m_version; - const eclass_t *m_eclass; - - /*! AABB in local space */ - aabb_t m_BBox; - - /*! worldspace-to-localspace translation */ - vec3_t m_translate; - - /*! worldspace-to-localspace euler rotation angles */ - vec3_t m_euler; - - /*! worldspace-to-localspace scale */ - vec3_t m_scale; - - /*! localspace origin, effectively rotation & scale pivot point */ - vec3_t m_pivot; - - /*! worldspace-to-localspace transform, generated from translate/euler/scale/pivot */ - m4x4_t m_transform; - - /*! localspace-to-worldspace transform */ - m4x4_t m_inverse_transform; -}; - -void pivot_draw(const vec3_t pivot); -void Entity_UpdateClass(entity_t *e, const char* value); - -#endif /* _ENTITYMODEL_H_ */ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _ENTITYMODEL_H_ +#define _ENTITYMODEL_H_ + +#include "plugin.h" + +/*! simulates misc_model entity behaviours for rendering/selection/editing */ +class CEntityMiscModel : public IRender, public ISelect, public IEdit +{ +public: + CEntityMiscModel (entity_t *e); + virtual ~CEntityMiscModel (); + + void IncRef() { refCount++; } + void DecRef() { if(--refCount == 0) delete this; } + + // IRender + void Draw(int state, int rflags) const; + const aabb_t *GetAABB() const { return &m_BBox; } + + // ISelect + bool TestRay(const ray_t *ray, vec_t *dist) const; + //bool TestBox(const aabb_t aabb) const; + + // ITransform + void Translate(const vec3_t translation); + void Rotate(const vec3_t pivot, const vec3_t rotation); + const vec_t *GetTranslation() const { return m_translate; } + const vec_t *GetRotation() const { return m_euler; } + void OnKeyValueChanged(entity_t *e, const char *key, const char* value); + + void SetName(const char *name); +private: + void BuildCacheRequestString(const char *name); + /*! updates the AABB and transformation matrix */ + void UpdateCachedData(); + entity_interfaces_t *m_model; + + entity_t *m_entity; + + int refCount; + string_t m_version; + + Str m_cachereq; + + /*! AABB in local space */ + aabb_t m_BBox; + + /*! worldspace-to-localspace translation */ + vec3_t m_translate; + + /*! worldspace-to-localspace euler rotation angles */ + vec3_t m_euler; + + /*! worldspace-to-localspace scale */ + vec3_t m_scale; + + /*! localspace origin, effectively rotation & scale pivot point */ + vec3_t m_pivot; + + /*! worldspace-to-localspace transform, generated from translate/euler/scale/pivot */ + m4x4_t m_transform; + + /*! localspace-to-worldspace transform */ + m4x4_t m_inverse_transform; +}; + +/*! simulates eclass-model entity behaviours for rendering/selection/editing */ +class CEntityEclassModel : public IRender, public ISelect, public IEdit +{ +public: + CEntityEclassModel (); + virtual ~CEntityEclassModel (); + + void IncRef() { refCount++; } + void DecRef() { if(--refCount == 0) delete this; } + + // IRender + void Draw(int state, int rflags) const; + const aabb_t *GetAABB() const { return &m_BBox; } + + // ISelect + bool TestRay(const ray_t *ray, vec_t *dist) const; + //bool TestBox(const aabb_t aabb) const; + + // ITransform + void Translate(const vec3_t translation); + void Rotate(const vec3_t pivot, const vec3_t rotation); + const vec_t *GetTranslation() const { return m_translate; } + const vec_t *GetRotation() const { return m_euler; } + void OnKeyValueChanged(entity_t *e, const char *key, const char* value); + + void SetName(const char *name); + void SetEclass(const eclass_t* eclass); +private: + /*! updates the AABB and transformation matrix */ + void UpdateCachedData(); + entity_interfaces_t *m_model; + + int refCount; + string_t m_name; + string_t m_version; + const eclass_t *m_eclass; + + /*! AABB in local space */ + aabb_t m_BBox; + + /*! worldspace-to-localspace translation */ + vec3_t m_translate; + + /*! worldspace-to-localspace euler rotation angles */ + vec3_t m_euler; + + /*! worldspace-to-localspace scale */ + vec3_t m_scale; + + /*! localspace origin, effectively rotation & scale pivot point */ + vec3_t m_pivot; + + /*! worldspace-to-localspace transform, generated from translate/euler/scale/pivot */ + m4x4_t m_transform; + + /*! localspace-to-worldspace transform */ + m4x4_t m_inverse_transform; +}; + +void pivot_draw(const vec3_t pivot); +void Entity_UpdateClass(entity_t *e, const char* value); + +#endif /* _ENTITYMODEL_H_ */ diff --git a/plugins/entity/light.h b/plugins/entity/light.h index 9beea359..37b714f2 100644 --- a/plugins/entity/light.h +++ b/plugins/entity/light.h @@ -1,26 +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 -*/ - -bool Entity_IsLight(entity_t *e); -void Light_OnKeyValueChanged(entity_t *e, const char *key, const char* value); -void DrawLight(entity_t* e, int nGLState, int pref, int nViewType); - + +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +bool Entity_IsLight(entity_t *e); +void Light_OnKeyValueChanged(entity_t *e, const char *key, const char* value); +void DrawLight(entity_t* e, int nGLState, int pref, int nViewType); + diff --git a/plugins/entity/plugin.h b/plugins/entity/plugin.h index 5bf34364..1c997440 100644 --- a/plugins/entity/plugin.h +++ b/plugins/entity/plugin.h @@ -1,58 +1,58 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 <stdio.h> - -#include "synapse.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#include "ientity.h" -#define USE_ECLASSMANAGER_DEFINE -#include "ieclass.h" -#define USE_BRUSHTABLE_DEFINE -#include "ibrush.h" -#define USE_UNDOTABLE_DEFINE -#include "iundo.h" -#include "imodel.h" -#include "igl.h" - -extern _QERFuncTable_1 g_FuncTable; -extern _QERQglTable g_QglTable; -extern _QERBrushTable __BRUSHTABLENAME; -extern _QERUndoTable __UNDOTABLENAME; -extern _EClassManagerTable __ECLASSMANAGERTABLENAME; - -#define Error g_FuncTable.m_pfnError - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> + +#include "synapse.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ientity.h" +#define USE_ECLASSMANAGER_DEFINE +#include "ieclass.h" +#define USE_BRUSHTABLE_DEFINE +#include "ibrush.h" +#define USE_UNDOTABLE_DEFINE +#include "iundo.h" +#include "imodel.h" +#include "igl.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERBrushTable __BRUSHTABLENAME; +extern _QERUndoTable __UNDOTABLENAME; +extern _EClassManagerTable __ECLASSMANAGERTABLENAME; + +#define Error g_FuncTable.m_pfnError + +#endif // _PLUGIN_H_ diff --git a/plugins/image/bmp.h b/plugins/image/bmp.h index c246f172..63667ea5 100644 --- a/plugins/image/bmp.h +++ b/plugins/image/bmp.h @@ -1,101 +1,101 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _BMP_H -#define _BMP_H - -#define xBI_NONE 0 -#define xBI_RGB 0 -#define xBI_RLE4 2 -#define xBI_RLE8 1 - -#define BMP_SIGNATURE_WORD 0x4d42 - -#pragma pack(1) - - - -typedef struct { - unsigned short bfType; // signature - 'BM' - unsigned long bfSize; // file size in bytes - unsigned short bfReserved1; // 0 - unsigned short bfReserved2; // 0 - unsigned long bfOffBits; // offset to bitmap -} bmphd_t; - - - -typedef struct { - unsigned long biSize; // size of this struct - long biWidth; // bmap width in pixels - long biHeight; // bmap height in pixels - unsigned short biPlanes; // num planes - always 1 - unsigned short biBitCount; // bits perpixel - unsigned long biCompression; // compression flag - unsigned long biSizeImage; // image size in bytes - long biXPelsPerMeter; // horz resolution - long biYPelsPerMeter; // vert resolution - unsigned long biClrUsed; // 0 -> color table size - unsigned long biClrImportant; // important color count -} binfo_t; - - -typedef struct { - unsigned char blue; - unsigned char green; - unsigned char red; - unsigned char reserved; -} drgb_t; - - -// quake expects its palette to be bgr -// this is totally backwards but what can you do -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; -} rgb_t; - - -typedef struct { - unsigned char b; - unsigned char g; - unsigned char r; -} bgr_t; - - -typedef struct { - int bpp; // bits per pixel - int width; - int height; - unsigned char *data; - rgb_t *palette; -} bitmap_t; - - -void LoadBMP(char *filename, bitmap_t *bit); -void FreeBMP(bitmap_t *bitmap); -void WriteBMP(char *filename, bitmap_t *bit); -void NewBMP(int width, int height, int bpp, bitmap_t *bit); - - - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _BMP_H +#define _BMP_H + +#define xBI_NONE 0 +#define xBI_RGB 0 +#define xBI_RLE4 2 +#define xBI_RLE8 1 + +#define BMP_SIGNATURE_WORD 0x4d42 + +#pragma pack(1) + + + +typedef struct { + unsigned short bfType; // signature - 'BM' + unsigned long bfSize; // file size in bytes + unsigned short bfReserved1; // 0 + unsigned short bfReserved2; // 0 + unsigned long bfOffBits; // offset to bitmap +} bmphd_t; + + + +typedef struct { + unsigned long biSize; // size of this struct + long biWidth; // bmap width in pixels + long biHeight; // bmap height in pixels + unsigned short biPlanes; // num planes - always 1 + unsigned short biBitCount; // bits perpixel + unsigned long biCompression; // compression flag + unsigned long biSizeImage; // image size in bytes + long biXPelsPerMeter; // horz resolution + long biYPelsPerMeter; // vert resolution + unsigned long biClrUsed; // 0 -> color table size + unsigned long biClrImportant; // important color count +} binfo_t; + + +typedef struct { + unsigned char blue; + unsigned char green; + unsigned char red; + unsigned char reserved; +} drgb_t; + + +// quake expects its palette to be bgr +// this is totally backwards but what can you do +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + + +typedef struct { + unsigned char b; + unsigned char g; + unsigned char r; +} bgr_t; + + +typedef struct { + int bpp; // bits per pixel + int width; + int height; + unsigned char *data; + rgb_t *palette; +} bitmap_t; + + +void LoadBMP(char *filename, bitmap_t *bit); +void FreeBMP(bitmap_t *bitmap); +void WriteBMP(char *filename, bitmap_t *bit); +void NewBMP(int width, int height, int bpp, bitmap_t *bit); + + + +#endif diff --git a/plugins/image/image.h b/plugins/image/image.h index f50e5a3e..f209fd59 100644 --- a/plugins/image/image.h +++ b/plugins/image/image.h @@ -1,68 +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 _IMAGE_H_ -#define _IMAGE_H_ - -#include "synapse.h" -#include "qerplugin.h" -#include "ifilesystem.h" -#include "iimage.h" - -#ifdef __linux__ - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; - -#endif // __linux__ - -extern _QERFuncTable_1 g_FuncTable; -extern _QERFileSystemTable g_FileSystemTable; -void LoadJPG (const char *filename, unsigned char **pic, int *width, int *height); - -#define Error g_FuncTable.m_pfnError -#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile -#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile - -class CSynapseClientImage : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - bool OnActivate(); - const char* GetName() { return "image"; } - - CSynapseClientImage() { } - virtual ~CSynapseClientImage() { } -}; - -#endif // _IMAGE_H_ +/* +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 _IMAGE_H_ +#define _IMAGE_H_ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" +#include "iimage.h" + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +extern _QERFuncTable_1 g_FuncTable; +extern _QERFileSystemTable g_FileSystemTable; +void LoadJPG (const char *filename, unsigned char **pic, int *width, int *height); + +#define Error g_FuncTable.m_pfnError +#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile +#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile + +class CSynapseClientImage : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + bool OnActivate(); + const char* GetName() { return "image"; } + + CSynapseClientImage() { } + virtual ~CSynapseClientImage() { } +}; + +#endif // _IMAGE_H_ diff --git a/plugins/image/lbmlib.h b/plugins/image/lbmlib.h index f0dccd4a..a8892be6 100644 --- a/plugins/image/lbmlib.h +++ b/plugins/image/lbmlib.h @@ -1,46 +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 -*/ - -// piclib.h - -#ifdef __linux__ -#define WINAPI -#endif - -typedef unsigned char byte; - -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); -// LoadImage will rely on file extension to call LoadTGA LoadPCX32 LoadBMP LoadJPG -void LoadImage( const char *name, byte **pic, int *width, int *height ); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 + +#ifdef __linux__ +#define WINAPI +#endif + +typedef unsigned char byte; + +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); +// LoadImage will rely on file extension to call LoadTGA LoadPCX32 LoadBMP LoadJPG +void LoadImage( const char *name, byte **pic, int *width, int *height ); diff --git a/plugins/imagehl/imagehl.h b/plugins/imagehl/imagehl.h index 26d82964..5042e7e2 100644 --- a/plugins/imagehl/imagehl.h +++ b/plugins/imagehl/imagehl.h @@ -1,80 +1,80 @@ -/* -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 _IMAGEHL_H_ -#define _IMAGEHL_H_ - -// here we can turn on and off which image formats this .dll will provide. -// just comment the define out to completly remove the code from the .dll. -#define USE_TARGA //Hydra: USE_TARGA is NOT required for HL support. but it might be useful to mappers. remove ? -#define USE_IDSP -#define USE_HLW -#define USE_MIP - -// on with the usual stuff... -#include "synapse.h" -#include "qerplugin.h" -#include "ifilesystem.h" -#include "iimage.h" - -#ifdef __linux__ - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; - -#endif // __linux__ - -extern _QERFuncTable_1 g_FuncTable; -extern _QERFileSystemTable g_FileSystemTable; - -#define Error g_FuncTable.m_pfnError -#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile -#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile - -#define LittleLong(a) GINT32_FROM_LE(a) -#define LittleShort(a) GINT16_FROM_LE(a) - -class CSynapseClientImageHL : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - CSynapseClientImageHL() { } - virtual ~CSynapseClientImageHL() { } -}; - -#define DWORD unsigned int -#define BYTE unsigned char -#define WORD unsigned short int - -#endif // _IMAGEHL_H_ +/* +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 _IMAGEHL_H_ +#define _IMAGEHL_H_ + +// here we can turn on and off which image formats this .dll will provide. +// just comment the define out to completly remove the code from the .dll. +#define USE_TARGA //Hydra: USE_TARGA is NOT required for HL support. but it might be useful to mappers. remove ? +#define USE_IDSP +#define USE_HLW +#define USE_MIP + +// on with the usual stuff... +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" +#include "iimage.h" + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +extern _QERFuncTable_1 g_FuncTable; +extern _QERFileSystemTable g_FileSystemTable; + +#define Error g_FuncTable.m_pfnError +#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile +#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile + +#define LittleLong(a) GINT32_FROM_LE(a) +#define LittleShort(a) GINT16_FROM_LE(a) + +class CSynapseClientImageHL : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientImageHL() { } + virtual ~CSynapseClientImageHL() { } +}; + +#define DWORD unsigned int +#define BYTE unsigned char +#define WORD unsigned short int + +#endif // _IMAGEHL_H_ diff --git a/plugins/imagehl/lbmlib.h b/plugins/imagehl/lbmlib.h index 2ea0ec5d..c50318bf 100644 --- a/plugins/imagehl/lbmlib.h +++ b/plugins/imagehl/lbmlib.h @@ -1,35 +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 -*/ - -// lbmlib.h - -#ifdef __linux__ -#define WINAPI -#endif - -typedef unsigned char byte; - -#ifdef USE_TARGA -void LoadTGA (char *filename, byte **pixels, int *width, int *height); -#endif - -// LoadImage will rely on file extension to call LoadTGA loadHLW -void LoadImage( const char *name, byte **pic, int *width, int *height ); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h + +#ifdef __linux__ +#define WINAPI +#endif + +typedef unsigned char byte; + +#ifdef USE_TARGA +void LoadTGA (char *filename, byte **pixels, int *width, int *height); +#endif + +// LoadImage will rely on file extension to call LoadTGA loadHLW +void LoadImage( const char *name, byte **pic, int *width, int *height ); diff --git a/plugins/imagem8/imagem8.h b/plugins/imagem8/imagem8.h index 9864256c..2ba99e89 100644 --- a/plugins/imagem8/imagem8.h +++ b/plugins/imagem8/imagem8.h @@ -1,70 +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. -*/ - -#ifndef _IMAGEM8_H_ -#define _IMAGEM8_H_ - -#include "synapse.h" -#include "qerplugin.h" -#include "ifilesystem.h" -#include "iimage.h" - -#ifdef __linux__ - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; - -#endif // __linux__ - -extern _QERFuncTable_1 g_FuncTable; -extern _QERFileSystemTable g_FileSystemTable; -void LoadM8 (const char *name, unsigned char **pic, int *width, int *height); -void LoadM32 (const char *name, unsigned char **pic, int *width, int *height); - -#define Error g_FuncTable.m_pfnError -#define Sys_Printf g_FuncTable.m_pfnSysPrintf -#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile -#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile - -class CSynapseClientImage : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - bool OnActivate(); - const char* GetName() { return "image"; } - - CSynapseClientImage() { } - virtual ~CSynapseClientImage() { } -}; - -#endif // _IMAGEM8_H_ +/* +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 _IMAGEM8_H_ +#define _IMAGEM8_H_ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" +#include "iimage.h" + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +extern _QERFuncTable_1 g_FuncTable; +extern _QERFileSystemTable g_FileSystemTable; +void LoadM8 (const char *name, unsigned char **pic, int *width, int *height); +void LoadM32 (const char *name, unsigned char **pic, int *width, int *height); + +#define Error g_FuncTable.m_pfnError +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile +#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile + +class CSynapseClientImage : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + bool OnActivate(); + const char* GetName() { return "image"; } + + CSynapseClientImage() { } + virtual ~CSynapseClientImage() { } +}; + +#endif // _IMAGEM8_H_ diff --git a/plugins/imagem8/m32.h b/plugins/imagem8/m32.h index 3b754130..4e49f4e5 100644 --- a/plugins/imagem8/m32.h +++ b/plugins/imagem8/m32.h @@ -1,64 +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 -*/ - -#ifndef _M32_H -#define _M32_H - -#include "imagem8.h" - -#define M32_VERSION 4 -#define M32_MIP_LEVELS 16 - -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; -} rgb_t; - -typedef struct -{ - 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[M32_MIP_LEVELS], height[M32_MIP_LEVELS]; - unsigned offsets[M32_MIP_LEVELS]; - 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 -} m32_header_t; - -void LoadM32(const char *name, unsigned char **pic, int *width, int *height); - - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _M32_H +#define _M32_H + +#include "imagem8.h" + +#define M32_VERSION 4 +#define M32_MIP_LEVELS 16 + +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + +typedef struct +{ + 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[M32_MIP_LEVELS], height[M32_MIP_LEVELS]; + unsigned offsets[M32_MIP_LEVELS]; + 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 +} m32_header_t; + +void LoadM32(const char *name, unsigned char **pic, int *width, int *height); + + +#endif diff --git a/plugins/imagem8/m8.h b/plugins/imagem8/m8.h index da187eff..d3c1caec 100644 --- a/plugins/imagem8/m8.h +++ b/plugins/imagem8/m8.h @@ -1,61 +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 _M8_H -#define _M8_H - -#include "imagem8.h" - -#define M8_VERSION 2 -#define PALETTE_SIZE 256 -#define MIP_LEVELS 16 - -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; -} rgb_t; - -typedef struct -{ - int version; - char name[32]; - unsigned width[MIP_LEVELS], height[MIP_LEVELS]; - unsigned offsets[MIP_LEVELS]; - char animname[32]; - rgb_t palette[PALETTE_SIZE]; - int flags; - int contents; - int value; -} m8_header_t; -/* -typedef struct { - int bpp; - int width; - int height; - unsigned char *data; - rgb_t *palette; -} m8_t; -*/ -void LoadM8(const char *name, unsigned char **pic, int *width, int *height); - - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _M8_H +#define _M8_H + +#include "imagem8.h" + +#define M8_VERSION 2 +#define PALETTE_SIZE 256 +#define MIP_LEVELS 16 + +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + +typedef struct +{ + int version; + char name[32]; + unsigned width[MIP_LEVELS], height[MIP_LEVELS]; + unsigned offsets[MIP_LEVELS]; + char animname[32]; + rgb_t palette[PALETTE_SIZE]; + int flags; + int contents; + int value; +} m8_header_t; +/* +typedef struct { + int bpp; + int width; + int height; + unsigned char *data; + rgb_t *palette; +} m8_t; +*/ +void LoadM8(const char *name, unsigned char **pic, int *width, int *height); + + +#endif diff --git a/plugins/imagepng/plugin.h b/plugins/imagepng/plugin.h index e0ef4b2e..c52b50bb 100644 --- a/plugins/imagepng/plugin.h +++ b/plugins/imagepng/plugin.h @@ -1,31 +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 _PLUGIN_H_ -#define _PLUGIN_H_ - -#include "qerplugin.h" -#include "iimage.h" -#include "ifilesystem.h" - -void LoadImage (const char *filename, unsigned char **pic, int *width, int *height); - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 "qerplugin.h" +#include "iimage.h" +#include "ifilesystem.h" + +void LoadImage (const char *filename, unsigned char **pic, int *width, int *height); + +#endif // _PLUGIN_H_ diff --git a/plugins/imagewal/imagewal.h b/plugins/imagewal/imagewal.h index cf5332b0..b9c8081b 100644 --- a/plugins/imagewal/imagewal.h +++ b/plugins/imagewal/imagewal.h @@ -1,60 +1,60 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _IMAGEWAL_H_ -#define _IMAGEWAL_H_ - -#include "synapse.h" -#include "qerplugin.h" -#include "ifilesystem.h" -#include "iimage.h" - -#ifdef __linux__ - -typedef void* HMODULE; -typedef void* LPVOID; -typedef char* LPCSTR; - -#endif // __linux__ - -extern _QERFuncTable_1 g_FuncTable; -extern _QERFileSystemTable g_FileSystemTable; -void LoadWAL (const char *filename, unsigned char **pic, int *width, int *height); - -#define Error g_FuncTable.m_pfnError -#define Sys_Printf g_FuncTable.m_pfnSysPrintf -#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile -#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile - -class CSynapseClientImage : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - bool OnActivate(); - const char* GetName() { return "image"; } - - CSynapseClientImage() { } - virtual ~CSynapseClientImage() { } -}; - -#endif // _IMAGEWAL_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _IMAGEWAL_H_ +#define _IMAGEWAL_H_ + +#include "synapse.h" +#include "qerplugin.h" +#include "ifilesystem.h" +#include "iimage.h" + +#ifdef __linux__ + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; + +#endif // __linux__ + +extern _QERFuncTable_1 g_FuncTable; +extern _QERFileSystemTable g_FileSystemTable; +void LoadWAL (const char *filename, unsigned char **pic, int *width, int *height); + +#define Error g_FuncTable.m_pfnError +#define Sys_Printf g_FuncTable.m_pfnSysPrintf +#define vfsLoadFile g_FileSystemTable.m_pfnLoadFile +#define vfsFreeFile g_FileSystemTable.m_pfnFreeFile + +class CSynapseClientImage : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + bool OnActivate(); + const char* GetName() { return "image"; } + + CSynapseClientImage() { } + virtual ~CSynapseClientImage() { } +}; + +#endif // _IMAGEWAL_H_ diff --git a/plugins/imagewal/q2_palette.h b/plugins/imagewal/q2_palette.h index 7c0bb02f..7479d3c4 100644 --- a/plugins/imagewal/q2_palette.h +++ b/plugins/imagewal/q2_palette.h @@ -1,66 +1,66 @@ -unsigned char quake2_palette[256][3] = { -{ 0x0, 0x0 , 0x0 }, { 0xF, 0xF , 0xF }, { 0x1F, 0x1F , 0x1F }, { 0x2F, 0x2F , 0x2F }, -{ 0x3F, 0x3F , 0x3F }, { 0x4B, 0x4B , 0x4B }, { 0x5B, 0x5B , 0x5B }, { 0x6B, 0x6B , 0x6B }, -{ 0x7B, 0x7B , 0x7B }, { 0x8B, 0x8B , 0x8B }, { 0x9B, 0x9B , 0x9B }, { 0xAB, 0xAB , 0xAB }, -{ 0xBB, 0xBB , 0xBB }, { 0xCB, 0xCB , 0xCB }, { 0xDB, 0xDB , 0xDB }, { 0xEB, 0xEB , 0xEB }, -{ 0x63, 0x4B , 0x23 }, { 0x5B, 0x43 , 0x1F }, { 0x53, 0x3F , 0x1F }, { 0x4F, 0x3B , 0x1B }, -{ 0x47, 0x37 , 0x1B }, { 0x3F, 0x2F , 0x17 }, { 0x3B, 0x2B , 0x17 }, { 0x33, 0x27 , 0x13 }, -{ 0x2F, 0x23 , 0x13 }, { 0x2B, 0x1F , 0x13 }, { 0x27, 0x1B , 0xF }, { 0x23, 0x17 , 0xF }, -{ 0x1B, 0x13 , 0xB }, { 0x17, 0xF , 0xB }, { 0x13, 0xF , 0x7 }, { 0xF, 0xB , 0x7 }, -{ 0x5F, 0x5F , 0x6F }, { 0x5B, 0x5B , 0x67 }, { 0x5B, 0x53 , 0x5F }, { 0x57, 0x4F , 0x5B }, -{ 0x53, 0x4B , 0x53 }, { 0x4F, 0x47 , 0x4B }, { 0x47, 0x3F , 0x43 }, { 0x3F, 0x3B , 0x3B }, -{ 0x3B, 0x37 , 0x37 }, { 0x33, 0x2F , 0x2F }, { 0x2F, 0x2B , 0x2B }, { 0x27, 0x27 , 0x27 }, -{ 0x23, 0x23 , 0x23 }, { 0x1B, 0x1B , 0x1B }, { 0x17, 0x17 , 0x17 }, { 0x13, 0x13 , 0x13 }, -{ 0x8F, 0x77 , 0x53 }, { 0x7B, 0x63 , 0x43 }, { 0x73, 0x5B , 0x3B }, { 0x67, 0x4F , 0x2F }, -{ 0xCF, 0x97 , 0x4B }, { 0xA7, 0x7B , 0x3B }, { 0x8B, 0x67 , 0x2F }, { 0x6F, 0x53 , 0x27 }, -{ 0xEB, 0x9F , 0x27 }, { 0xCB, 0x8B , 0x23 }, { 0xAF, 0x77 , 0x1F }, { 0x93, 0x63 , 0x1B }, -{ 0x77, 0x4F , 0x17 }, { 0x5B, 0x3B , 0xF }, { 0x3F, 0x27 , 0xB }, { 0x23, 0x17 , 0x7 }, -{ 0xA7, 0x3B , 0x2B }, { 0x9F, 0x2F , 0x23 }, { 0x97, 0x2B , 0x1B }, { 0x8B, 0x27 , 0x13 }, -{ 0x7F, 0x1F , 0xF }, { 0x73, 0x17 , 0xB }, { 0x67, 0x17 , 0x7 }, { 0x57, 0x13 , 0x0 }, -{ 0x4B, 0xF , 0x0 }, { 0x43, 0xF , 0x0 }, { 0x3B, 0xF , 0x0 }, { 0x33, 0xB , 0x0 }, -{ 0x2B, 0xB , 0x0 }, { 0x23, 0xB , 0x0 }, { 0x1B, 0x7 , 0x0 }, { 0x13, 0x7 , 0x0 }, -{ 0x7B, 0x5F , 0x4B }, { 0x73, 0x57 , 0x43 }, { 0x6B, 0x53 , 0x3F }, { 0x67, 0x4F , 0x3B }, -{ 0x5F, 0x47 , 0x37 }, { 0x57, 0x43 , 0x33 }, { 0x53, 0x3F , 0x2F }, { 0x4B, 0x37 , 0x2B }, -{ 0x43, 0x33 , 0x27 }, { 0x3F, 0x2F , 0x23 }, { 0x37, 0x27 , 0x1B }, { 0x2F, 0x23 , 0x17 }, -{ 0x27, 0x1B , 0x13 }, { 0x1F, 0x17 , 0xF }, { 0x17, 0xF , 0xB }, { 0xF, 0xB , 0x7 }, -{ 0x6F, 0x3B , 0x17 }, { 0x5F, 0x37 , 0x17 }, { 0x53, 0x2F , 0x17 }, { 0x43, 0x2B , 0x17 }, -{ 0x37, 0x23 , 0x13 }, { 0x27, 0x1B , 0xF }, { 0x1B, 0x13 , 0xB }, { 0xF, 0xB , 0x7 }, -{ 0xB3, 0x5B , 0x4F }, { 0xBF, 0x7B , 0x6F }, { 0xCB, 0x9B , 0x93 }, { 0xD7, 0xBB , 0xB7 }, -{ 0xCB, 0xD7 , 0xDF }, { 0xB3, 0xC7 , 0xD3 }, { 0x9F, 0xB7 , 0xC3 }, { 0x87, 0xA7 , 0xB7 }, -{ 0x73, 0x97 , 0xA7 }, { 0x5B, 0x87 , 0x9B }, { 0x47, 0x77 , 0x8B }, { 0x2F, 0x67 , 0x7F }, -{ 0x17, 0x53 , 0x6F }, { 0x13, 0x4B , 0x67 }, { 0xF, 0x43 , 0x5B }, { 0xB, 0x3F , 0x53 }, -{ 0x7, 0x37 , 0x4B }, { 0x7, 0x2F , 0x3F }, { 0x7, 0x27 , 0x33 }, { 0x0, 0x1F , 0x2B }, -{ 0x0, 0x17 , 0x1F }, { 0x0, 0xF , 0x13 }, { 0x0, 0x7 , 0xB }, { 0x0, 0x0 , 0x0 }, -{ 0x8B, 0x57 , 0x57 }, { 0x83, 0x4F , 0x4F }, { 0x7B, 0x47 , 0x47 }, { 0x73, 0x43 , 0x43 }, -{ 0x6B, 0x3B , 0x3B }, { 0x63, 0x33 , 0x33 }, { 0x5B, 0x2F , 0x2F }, { 0x57, 0x2B , 0x2B }, -{ 0x4B, 0x23 , 0x23 }, { 0x3F, 0x1F , 0x1F }, { 0x33, 0x1B , 0x1B }, { 0x2B, 0x13 , 0x13 }, -{ 0x1F, 0xF , 0xF }, { 0x13, 0xB , 0xB }, { 0xB, 0x7 , 0x7 }, { 0x0, 0x0 , 0x0 }, -{ 0x97, 0x9F , 0x7B }, { 0x8F, 0x97 , 0x73 }, { 0x87, 0x8B , 0x6B }, { 0x7F, 0x83 , 0x63 }, -{ 0x77, 0x7B , 0x5F }, { 0x73, 0x73 , 0x57 }, { 0x6B, 0x6B , 0x4F }, { 0x63, 0x63 , 0x47 }, -{ 0x5B, 0x5B , 0x43 }, { 0x4F, 0x4F , 0x3B }, { 0x43, 0x43 , 0x33 }, { 0x37, 0x37 , 0x2B }, -{ 0x2F, 0x2F , 0x23 }, { 0x23, 0x23 , 0x1B }, { 0x17, 0x17 , 0x13 }, { 0xF, 0xF , 0xB }, -{ 0x9F, 0x4B , 0x3F }, { 0x93, 0x43 , 0x37 }, { 0x8B, 0x3B , 0x2F }, { 0x7F, 0x37 , 0x27 }, -{ 0x77, 0x2F , 0x23 }, { 0x6B, 0x2B , 0x1B }, { 0x63, 0x23 , 0x17 }, { 0x57, 0x1F , 0x13 }, -{ 0x4F, 0x1B , 0xF }, { 0x43, 0x17 , 0xB }, { 0x37, 0x13 , 0xB }, { 0x2B, 0xF , 0x7 }, -{ 0x1F, 0xB , 0x7 }, { 0x17, 0x7 , 0x0 }, { 0xB, 0x0 , 0x0 }, { 0x0, 0x0 , 0x0 }, -{ 0x77, 0x7B , 0xCF }, { 0x6F, 0x73 , 0xC3 }, { 0x67, 0x6B , 0xB7 }, { 0x63, 0x63 , 0xA7 }, -{ 0x5B, 0x5B , 0x9B }, { 0x53, 0x57 , 0x8F }, { 0x4B, 0x4F , 0x7F }, { 0x47, 0x47 , 0x73 }, -{ 0x3F, 0x3F , 0x67 }, { 0x37, 0x37 , 0x57 }, { 0x2F, 0x2F , 0x4B }, { 0x27, 0x27 , 0x3F }, -{ 0x23, 0x1F , 0x2F }, { 0x1B, 0x17 , 0x23 }, { 0x13, 0xF , 0x17 }, { 0xB, 0x7 , 0x7 }, -{ 0x9B, 0xAB , 0x7B }, { 0x8F, 0x9F , 0x6F }, { 0x87, 0x97 , 0x63 }, { 0x7B, 0x8B , 0x57 }, -{ 0x73, 0x83 , 0x4B }, { 0x67, 0x77 , 0x43 }, { 0x5F, 0x6F , 0x3B }, { 0x57, 0x67 , 0x33 }, -{ 0x4B, 0x5B , 0x27 }, { 0x3F, 0x4F , 0x1B }, { 0x37, 0x43 , 0x13 }, { 0x2F, 0x3B , 0xB }, -{ 0x23, 0x2F , 0x7 }, { 0x1B, 0x23 , 0x0 }, { 0x13, 0x17 , 0x0 }, { 0xB, 0xF , 0x0 }, -{ 0x0, 0xFF , 0x0 }, { 0x23, 0xE7 , 0xF }, { 0x3F, 0xD3 , 0x1B }, { 0x53, 0xBB , 0x27 }, -{ 0x5F, 0xA7 , 0x2F }, { 0x5F, 0x8F , 0x33 }, { 0x5F, 0x7B , 0x33 }, { 0xFF, 0xFF , 0xFF }, -{ 0xFF, 0xFF , 0xD3 }, { 0xFF, 0xFF , 0xA7 }, { 0xFF, 0xFF , 0x7F }, { 0xFF, 0xFF , 0x53 }, -{ 0xFF, 0xFF , 0x27 }, { 0xFF, 0xEB , 0x1F }, { 0xFF, 0xD7 , 0x17 }, { 0xFF, 0xBF , 0xF }, -{ 0xFF, 0xAB , 0x7 }, { 0xFF, 0x93 , 0x0 }, { 0xEF, 0x7F , 0x0 }, { 0xE3, 0x6B , 0x0 }, -{ 0xD3, 0x57 , 0x0 }, { 0xC7, 0x47 , 0x0 }, { 0xB7, 0x3B , 0x0 }, { 0xAB, 0x2B , 0x0 }, -{ 0x9B, 0x1F , 0x0 }, { 0x8F, 0x17 , 0x0 }, { 0x7F, 0xF , 0x0 }, { 0x73, 0x7 , 0x0 }, -{ 0x5F, 0x0 , 0x0 }, { 0x47, 0x0 , 0x0 }, { 0x2F, 0x0 , 0x0 }, { 0x1B, 0x0 , 0x0 }, -{ 0xEF, 0x0 , 0x0 }, { 0x37, 0x37 , 0xFF }, { 0xFF, 0x0 , 0x0 }, { 0x0, 0x0 , 0xFF }, -{ 0x2B, 0x2B , 0x23 }, { 0x1B, 0x1B , 0x17 }, { 0x13, 0x13 , 0xF }, { 0xEB, 0x97 , 0x7F }, -{ 0xC3, 0x73 , 0x53 }, { 0x9F, 0x57 , 0x33 }, { 0x7B, 0x3F , 0x1B }, { 0xEB, 0xD3 , 0xC7 }, -{ 0xC7, 0xAB , 0x9B }, { 0xA7, 0x8B , 0x77 }, { 0x87, 0x6B , 0x57 }, { 0x9F, 0x5B , 0x53 } -}; +unsigned char quake2_palette[256][3] = { +{ 0x0, 0x0 , 0x0 }, { 0xF, 0xF , 0xF }, { 0x1F, 0x1F , 0x1F }, { 0x2F, 0x2F , 0x2F }, +{ 0x3F, 0x3F , 0x3F }, { 0x4B, 0x4B , 0x4B }, { 0x5B, 0x5B , 0x5B }, { 0x6B, 0x6B , 0x6B }, +{ 0x7B, 0x7B , 0x7B }, { 0x8B, 0x8B , 0x8B }, { 0x9B, 0x9B , 0x9B }, { 0xAB, 0xAB , 0xAB }, +{ 0xBB, 0xBB , 0xBB }, { 0xCB, 0xCB , 0xCB }, { 0xDB, 0xDB , 0xDB }, { 0xEB, 0xEB , 0xEB }, +{ 0x63, 0x4B , 0x23 }, { 0x5B, 0x43 , 0x1F }, { 0x53, 0x3F , 0x1F }, { 0x4F, 0x3B , 0x1B }, +{ 0x47, 0x37 , 0x1B }, { 0x3F, 0x2F , 0x17 }, { 0x3B, 0x2B , 0x17 }, { 0x33, 0x27 , 0x13 }, +{ 0x2F, 0x23 , 0x13 }, { 0x2B, 0x1F , 0x13 }, { 0x27, 0x1B , 0xF }, { 0x23, 0x17 , 0xF }, +{ 0x1B, 0x13 , 0xB }, { 0x17, 0xF , 0xB }, { 0x13, 0xF , 0x7 }, { 0xF, 0xB , 0x7 }, +{ 0x5F, 0x5F , 0x6F }, { 0x5B, 0x5B , 0x67 }, { 0x5B, 0x53 , 0x5F }, { 0x57, 0x4F , 0x5B }, +{ 0x53, 0x4B , 0x53 }, { 0x4F, 0x47 , 0x4B }, { 0x47, 0x3F , 0x43 }, { 0x3F, 0x3B , 0x3B }, +{ 0x3B, 0x37 , 0x37 }, { 0x33, 0x2F , 0x2F }, { 0x2F, 0x2B , 0x2B }, { 0x27, 0x27 , 0x27 }, +{ 0x23, 0x23 , 0x23 }, { 0x1B, 0x1B , 0x1B }, { 0x17, 0x17 , 0x17 }, { 0x13, 0x13 , 0x13 }, +{ 0x8F, 0x77 , 0x53 }, { 0x7B, 0x63 , 0x43 }, { 0x73, 0x5B , 0x3B }, { 0x67, 0x4F , 0x2F }, +{ 0xCF, 0x97 , 0x4B }, { 0xA7, 0x7B , 0x3B }, { 0x8B, 0x67 , 0x2F }, { 0x6F, 0x53 , 0x27 }, +{ 0xEB, 0x9F , 0x27 }, { 0xCB, 0x8B , 0x23 }, { 0xAF, 0x77 , 0x1F }, { 0x93, 0x63 , 0x1B }, +{ 0x77, 0x4F , 0x17 }, { 0x5B, 0x3B , 0xF }, { 0x3F, 0x27 , 0xB }, { 0x23, 0x17 , 0x7 }, +{ 0xA7, 0x3B , 0x2B }, { 0x9F, 0x2F , 0x23 }, { 0x97, 0x2B , 0x1B }, { 0x8B, 0x27 , 0x13 }, +{ 0x7F, 0x1F , 0xF }, { 0x73, 0x17 , 0xB }, { 0x67, 0x17 , 0x7 }, { 0x57, 0x13 , 0x0 }, +{ 0x4B, 0xF , 0x0 }, { 0x43, 0xF , 0x0 }, { 0x3B, 0xF , 0x0 }, { 0x33, 0xB , 0x0 }, +{ 0x2B, 0xB , 0x0 }, { 0x23, 0xB , 0x0 }, { 0x1B, 0x7 , 0x0 }, { 0x13, 0x7 , 0x0 }, +{ 0x7B, 0x5F , 0x4B }, { 0x73, 0x57 , 0x43 }, { 0x6B, 0x53 , 0x3F }, { 0x67, 0x4F , 0x3B }, +{ 0x5F, 0x47 , 0x37 }, { 0x57, 0x43 , 0x33 }, { 0x53, 0x3F , 0x2F }, { 0x4B, 0x37 , 0x2B }, +{ 0x43, 0x33 , 0x27 }, { 0x3F, 0x2F , 0x23 }, { 0x37, 0x27 , 0x1B }, { 0x2F, 0x23 , 0x17 }, +{ 0x27, 0x1B , 0x13 }, { 0x1F, 0x17 , 0xF }, { 0x17, 0xF , 0xB }, { 0xF, 0xB , 0x7 }, +{ 0x6F, 0x3B , 0x17 }, { 0x5F, 0x37 , 0x17 }, { 0x53, 0x2F , 0x17 }, { 0x43, 0x2B , 0x17 }, +{ 0x37, 0x23 , 0x13 }, { 0x27, 0x1B , 0xF }, { 0x1B, 0x13 , 0xB }, { 0xF, 0xB , 0x7 }, +{ 0xB3, 0x5B , 0x4F }, { 0xBF, 0x7B , 0x6F }, { 0xCB, 0x9B , 0x93 }, { 0xD7, 0xBB , 0xB7 }, +{ 0xCB, 0xD7 , 0xDF }, { 0xB3, 0xC7 , 0xD3 }, { 0x9F, 0xB7 , 0xC3 }, { 0x87, 0xA7 , 0xB7 }, +{ 0x73, 0x97 , 0xA7 }, { 0x5B, 0x87 , 0x9B }, { 0x47, 0x77 , 0x8B }, { 0x2F, 0x67 , 0x7F }, +{ 0x17, 0x53 , 0x6F }, { 0x13, 0x4B , 0x67 }, { 0xF, 0x43 , 0x5B }, { 0xB, 0x3F , 0x53 }, +{ 0x7, 0x37 , 0x4B }, { 0x7, 0x2F , 0x3F }, { 0x7, 0x27 , 0x33 }, { 0x0, 0x1F , 0x2B }, +{ 0x0, 0x17 , 0x1F }, { 0x0, 0xF , 0x13 }, { 0x0, 0x7 , 0xB }, { 0x0, 0x0 , 0x0 }, +{ 0x8B, 0x57 , 0x57 }, { 0x83, 0x4F , 0x4F }, { 0x7B, 0x47 , 0x47 }, { 0x73, 0x43 , 0x43 }, +{ 0x6B, 0x3B , 0x3B }, { 0x63, 0x33 , 0x33 }, { 0x5B, 0x2F , 0x2F }, { 0x57, 0x2B , 0x2B }, +{ 0x4B, 0x23 , 0x23 }, { 0x3F, 0x1F , 0x1F }, { 0x33, 0x1B , 0x1B }, { 0x2B, 0x13 , 0x13 }, +{ 0x1F, 0xF , 0xF }, { 0x13, 0xB , 0xB }, { 0xB, 0x7 , 0x7 }, { 0x0, 0x0 , 0x0 }, +{ 0x97, 0x9F , 0x7B }, { 0x8F, 0x97 , 0x73 }, { 0x87, 0x8B , 0x6B }, { 0x7F, 0x83 , 0x63 }, +{ 0x77, 0x7B , 0x5F }, { 0x73, 0x73 , 0x57 }, { 0x6B, 0x6B , 0x4F }, { 0x63, 0x63 , 0x47 }, +{ 0x5B, 0x5B , 0x43 }, { 0x4F, 0x4F , 0x3B }, { 0x43, 0x43 , 0x33 }, { 0x37, 0x37 , 0x2B }, +{ 0x2F, 0x2F , 0x23 }, { 0x23, 0x23 , 0x1B }, { 0x17, 0x17 , 0x13 }, { 0xF, 0xF , 0xB }, +{ 0x9F, 0x4B , 0x3F }, { 0x93, 0x43 , 0x37 }, { 0x8B, 0x3B , 0x2F }, { 0x7F, 0x37 , 0x27 }, +{ 0x77, 0x2F , 0x23 }, { 0x6B, 0x2B , 0x1B }, { 0x63, 0x23 , 0x17 }, { 0x57, 0x1F , 0x13 }, +{ 0x4F, 0x1B , 0xF }, { 0x43, 0x17 , 0xB }, { 0x37, 0x13 , 0xB }, { 0x2B, 0xF , 0x7 }, +{ 0x1F, 0xB , 0x7 }, { 0x17, 0x7 , 0x0 }, { 0xB, 0x0 , 0x0 }, { 0x0, 0x0 , 0x0 }, +{ 0x77, 0x7B , 0xCF }, { 0x6F, 0x73 , 0xC3 }, { 0x67, 0x6B , 0xB7 }, { 0x63, 0x63 , 0xA7 }, +{ 0x5B, 0x5B , 0x9B }, { 0x53, 0x57 , 0x8F }, { 0x4B, 0x4F , 0x7F }, { 0x47, 0x47 , 0x73 }, +{ 0x3F, 0x3F , 0x67 }, { 0x37, 0x37 , 0x57 }, { 0x2F, 0x2F , 0x4B }, { 0x27, 0x27 , 0x3F }, +{ 0x23, 0x1F , 0x2F }, { 0x1B, 0x17 , 0x23 }, { 0x13, 0xF , 0x17 }, { 0xB, 0x7 , 0x7 }, +{ 0x9B, 0xAB , 0x7B }, { 0x8F, 0x9F , 0x6F }, { 0x87, 0x97 , 0x63 }, { 0x7B, 0x8B , 0x57 }, +{ 0x73, 0x83 , 0x4B }, { 0x67, 0x77 , 0x43 }, { 0x5F, 0x6F , 0x3B }, { 0x57, 0x67 , 0x33 }, +{ 0x4B, 0x5B , 0x27 }, { 0x3F, 0x4F , 0x1B }, { 0x37, 0x43 , 0x13 }, { 0x2F, 0x3B , 0xB }, +{ 0x23, 0x2F , 0x7 }, { 0x1B, 0x23 , 0x0 }, { 0x13, 0x17 , 0x0 }, { 0xB, 0xF , 0x0 }, +{ 0x0, 0xFF , 0x0 }, { 0x23, 0xE7 , 0xF }, { 0x3F, 0xD3 , 0x1B }, { 0x53, 0xBB , 0x27 }, +{ 0x5F, 0xA7 , 0x2F }, { 0x5F, 0x8F , 0x33 }, { 0x5F, 0x7B , 0x33 }, { 0xFF, 0xFF , 0xFF }, +{ 0xFF, 0xFF , 0xD3 }, { 0xFF, 0xFF , 0xA7 }, { 0xFF, 0xFF , 0x7F }, { 0xFF, 0xFF , 0x53 }, +{ 0xFF, 0xFF , 0x27 }, { 0xFF, 0xEB , 0x1F }, { 0xFF, 0xD7 , 0x17 }, { 0xFF, 0xBF , 0xF }, +{ 0xFF, 0xAB , 0x7 }, { 0xFF, 0x93 , 0x0 }, { 0xEF, 0x7F , 0x0 }, { 0xE3, 0x6B , 0x0 }, +{ 0xD3, 0x57 , 0x0 }, { 0xC7, 0x47 , 0x0 }, { 0xB7, 0x3B , 0x0 }, { 0xAB, 0x2B , 0x0 }, +{ 0x9B, 0x1F , 0x0 }, { 0x8F, 0x17 , 0x0 }, { 0x7F, 0xF , 0x0 }, { 0x73, 0x7 , 0x0 }, +{ 0x5F, 0x0 , 0x0 }, { 0x47, 0x0 , 0x0 }, { 0x2F, 0x0 , 0x0 }, { 0x1B, 0x0 , 0x0 }, +{ 0xEF, 0x0 , 0x0 }, { 0x37, 0x37 , 0xFF }, { 0xFF, 0x0 , 0x0 }, { 0x0, 0x0 , 0xFF }, +{ 0x2B, 0x2B , 0x23 }, { 0x1B, 0x1B , 0x17 }, { 0x13, 0x13 , 0xF }, { 0xEB, 0x97 , 0x7F }, +{ 0xC3, 0x73 , 0x53 }, { 0x9F, 0x57 , 0x33 }, { 0x7B, 0x3F , 0x1B }, { 0xEB, 0xD3 , 0xC7 }, +{ 0xC7, 0xAB , 0x9B }, { 0xA7, 0x8B , 0x77 }, { 0x87, 0x6B , 0x57 }, { 0x9F, 0x5B , 0x53 } +}; diff --git a/plugins/imagewal/wal.h b/plugins/imagewal/wal.h index 40b1778b..a0afcbc0 100644 --- a/plugins/imagewal/wal.h +++ b/plugins/imagewal/wal.h @@ -1,51 +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 _WAL_H -#define _WAL_H - -#include "imagewal.h" - -#define PALETTE_SIZE 256 -#define MIPLEVELS 4 - -typedef struct { - unsigned char r; - unsigned char g; - unsigned char b; -} rgb_t; - - -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; - -void LoadWAL(const char *name, unsigned char **pic, int *width, int *height); - - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _WAL_H +#define _WAL_H + +#include "imagewal.h" + +#define PALETTE_SIZE 256 +#define MIPLEVELS 4 + +typedef struct { + unsigned char r; + unsigned char g; + unsigned char b; +} rgb_t; + + +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; + +void LoadWAL(const char *name, unsigned char **pic, int *width, int *height); + + +#endif diff --git a/plugins/map/plugin.h b/plugins/map/plugin.h index 89e586b0..e568135e 100644 --- a/plugins/map/plugin.h +++ b/plugins/map/plugin.h @@ -1,92 +1,92 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 <stdlib.h> -#include <stdio.h> - -#include "synapse.h" - -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#define USE_VFSTABLE_DEFINE -#define USE_SCRIPLIBTABLE_DEFINE -#include "iscriplib.h" -#include "imap.h" -#include "ishaders.h" -#define USE_ENTITYTABLE_DEFINE -#include "ientity.h" -#define USE_BRUSHTABLE_DEFINE -#include "ibrush.h" -#define USE_PATCHTABLE_DEFINE -#include "ipatch.h" -#define USE_VFSTABLE_DEFINE -#include "ifilesystem.h" - -extern _QERFuncTable_1 g_FuncTable; -extern _QERScripLibTable g_ScripLibTable; -extern _QERShadersTable g_ShadersTable; -extern _QEREntityTable __ENTITYTABLENAME; -extern _QERBrushTable g_BrushTable; -extern _QERPatchTable g_PatchTable; -extern _QERFileSystemTable g_FileSystemTable; - -#define Error g_FuncTable.m_pfnError -#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName - -// a bunch of globals to the module -extern void *g_pRadiantWnd; - -#define MAPVERSION_Q3 1 -#define MAPVERSION_HL 2 -#define MAPVERSION_Q2 3 -//#define MAPVERSION_Q1 - -#define MAP_NOERROR 0 -#define MAP_ABORTED 1 -#define MAP_WRONGVERSION 2 - -void Map_ReadQ3 (IDataStream *in, CPtrArray *map); -void Map_WriteQ3 (CPtrArray *map, IDataStream *out); -void Map_ReadHL (IDataStream *in, CPtrArray *map); -void Map_WriteHL (CPtrArray *map, IDataStream *out); -void Map_ReadQ2 (IDataStream *in, CPtrArray *map); -void Map_WriteQ2 (CPtrArray *map, IDataStream *out); - -extern CSynapseServer* g_pSynapseServer; - -class CSynapseClientMap : public CSynapseClient -{ - bool mbMapHL; -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); ///< required for runtime configuration - bool OnActivate(); - - CSynapseClientMap() { mbMapHL = false; } - virtual ~CSynapseClientMap() { } -}; - -#endif // _PLUGIN_H_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> +#include <stdio.h> + +#include "synapse.h" + +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#define USE_VFSTABLE_DEFINE +#define USE_SCRIPLIBTABLE_DEFINE +#include "iscriplib.h" +#include "imap.h" +#include "ishaders.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" +#define USE_BRUSHTABLE_DEFINE +#include "ibrush.h" +#define USE_PATCHTABLE_DEFINE +#include "ipatch.h" +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERScripLibTable g_ScripLibTable; +extern _QERShadersTable g_ShadersTable; +extern _QEREntityTable __ENTITYTABLENAME; +extern _QERBrushTable g_BrushTable; +extern _QERPatchTable g_PatchTable; +extern _QERFileSystemTable g_FileSystemTable; + +#define Error g_FuncTable.m_pfnError +#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName + +// a bunch of globals to the module +extern void *g_pRadiantWnd; + +#define MAPVERSION_Q3 1 +#define MAPVERSION_HL 2 +#define MAPVERSION_Q2 3 +//#define MAPVERSION_Q1 + +#define MAP_NOERROR 0 +#define MAP_ABORTED 1 +#define MAP_WRONGVERSION 2 + +void Map_ReadQ3 (IDataStream *in, CPtrArray *map); +void Map_WriteQ3 (CPtrArray *map, IDataStream *out); +void Map_ReadHL (IDataStream *in, CPtrArray *map); +void Map_WriteHL (CPtrArray *map, IDataStream *out); +void Map_ReadQ2 (IDataStream *in, CPtrArray *map); +void Map_WriteQ2 (CPtrArray *map, IDataStream *out); + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientMap : public CSynapseClient +{ + bool mbMapHL; +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); ///< required for runtime configuration + bool OnActivate(); + + CSynapseClientMap() { mbMapHL = false; } + virtual ~CSynapseClientMap() { } +}; + +#endif // _PLUGIN_H_ diff --git a/plugins/mapxml/plugin.h b/plugins/mapxml/plugin.h index 4529a651..a129b400 100644 --- a/plugins/mapxml/plugin.h +++ b/plugins/mapxml/plugin.h @@ -1,49 +1,49 @@ -#ifndef _PLUGIN_H_ -#define _PLUGIN_H_ - -#include <stdlib.h> -#include <stdio.h> - -#include "libxml/parser.h" - -#include "synapse.h" -#define USE_QERTABLE_DEFINE -#include "qerplugin.h" -#include "imap.h" -#include "ishaders.h" -#define USE_ENTITYTABLE_DEFINE -#include "ientity.h" -#define USE_BRUSHTABLE_DEFINE -#include "ibrush.h" -#define USE_PATCHTABLE_DEFINE -#include "ipatch.h" - -extern _QERFuncTable_1 g_FuncTable; -extern _QERShadersTable g_ShadersTable; -extern _QEREntityTable g_EntityTable; -extern _QERBrushTable g_BrushTable; -extern _QERPatchTable g_PatchTable; - -#define Error g_FuncTable.m_pfnError -#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName - -extern void *g_pRadiantWnd; - -void Map_Read (IDataStream *in, CPtrArray *map); -void Map_Write (CPtrArray *map, IDataStream *out); - -extern CSynapseServer* g_pSynapseServer; - -class CSynapseClientXMap : public CSynapseClient -{ -public: - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - const char* GetName(); ///< required for XML runtime config - - CSynapseClientXMap() { } - virtual ~CSynapseClientXMap() { } -}; - -#endif // _PLUGIN_H_ +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +#include <stdlib.h> +#include <stdio.h> + +#include "libxml/parser.h" + +#include "synapse.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "imap.h" +#include "ishaders.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" +#define USE_BRUSHTABLE_DEFINE +#include "ibrush.h" +#define USE_PATCHTABLE_DEFINE +#include "ipatch.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERShadersTable g_ShadersTable; +extern _QEREntityTable g_EntityTable; +extern _QERBrushTable g_BrushTable; +extern _QERPatchTable g_PatchTable; + +#define Error g_FuncTable.m_pfnError +#define QERApp_Shader_ForName g_ShadersTable.m_pfnShader_ForName + +extern void *g_pRadiantWnd; + +void Map_Read (IDataStream *in, CPtrArray *map); +void Map_Write (CPtrArray *map, IDataStream *out); + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientXMap : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); ///< required for XML runtime config + + CSynapseClientXMap() { } + virtual ~CSynapseClientXMap() { } +}; + +#endif // _PLUGIN_H_ diff --git a/plugins/model/cpicomodel.h b/plugins/model/cpicomodel.h index 13ebfe1e..938cede0 100644 --- a/plugins/model/cpicomodel.h +++ b/plugins/model/cpicomodel.h @@ -1,94 +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<Str, int> PicoModelKey; -typedef pair<Str, int> 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<IShader*> 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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<Str, int> PicoModelKey; +typedef pair<Str, int> 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<IShader*> 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.h b/plugins/model/cpicosurface.h index 51f6d7fc..41f523d2 100644 --- a/plugins/model/cpicosurface.h +++ b/plugins/model/cpicosurface.h @@ -1,55 +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 -*/ - -#include "plugin.h" -#include "picomodel.h" - -/*! Largest (potentially) selectable leaf of a Pico model */ -class CPicoSurface -{ -public: - CPicoSurface(picoSurface_t *surf); // creates a new surface from a picoSurface_t - ~CPicoSurface(); - - void IncRef() { refCount++; } - void DecRef() { if(--refCount == 0) delete this; } - - void Draw(int state, IShader *pShader, int rflags); - //IRender - void Draw(int state, int rflags); - const aabb_t *GetAABB() const { return &m_BBox; } - - //ISelect - bool TestRay (const ray_t *ray, vec_t *dist) const; - - char *GetShaderName( void ) - { - return PicoGetShaderName(m_pSurface->shader); - } - -private: - int refCount; - aabb_t m_BBox; - picoSurface_t *m_pSurface; - IShader* m_shader; - - void AccumulateBBox(); // accumulate local bbox.. generally created from control handles -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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" + +/*! Largest (potentially) selectable leaf of a Pico model */ +class CPicoSurface +{ +public: + CPicoSurface(picoSurface_t *surf); // creates a new surface from a picoSurface_t + ~CPicoSurface(); + + void IncRef() { refCount++; } + void DecRef() { if(--refCount == 0) delete this; } + + void Draw(int state, IShader *pShader, int rflags); + //IRender + void Draw(int state, int rflags); + const aabb_t *GetAABB() const { return &m_BBox; } + + //ISelect + bool TestRay (const ray_t *ray, vec_t *dist) const; + + char *GetShaderName( void ) + { + return PicoGetShaderName(m_pSurface->shader); + } + +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/plugin.h b/plugins/model/plugin.h index 06158646..b2ccccda 100644 --- a/plugins/model/plugin.h +++ b/plugins/model/plugin.h @@ -1,76 +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 <stdio.h> - -#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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> + +#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/surface.h b/plugins/model/surface.h index 33c5d2f7..43d9b276 100644 --- a/plugins/model/surface.h +++ b/plugins/model/surface.h @@ -1,38 +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; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/shaders/plugin.h index 6a4a547d..509e5e43 100644 --- a/plugins/shaders/plugin.h +++ b/plugins/shaders/plugin.h @@ -1,69 +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_ +/* +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.h b/plugins/shaders/shaders.h index 04792a59..253f87ec 100644 --- a/plugins/shaders/shaders.h +++ b/plugins/shaders/shaders.h @@ -1,167 +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 +/* +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/spritemodel/plugin.h b/plugins/spritemodel/plugin.h index e8ebe054..5dca12ee 100644 --- a/plugins/spritemodel/plugin.h +++ b/plugins/spritemodel/plugin.h @@ -1,78 +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 <stdio.h> - -#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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> + +#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.h b/plugins/spritemodel/spritemodel.h index 688c0e6a..c6c26305 100644 --- a/plugins/spritemodel/spritemodel.h +++ b/plugins/spritemodel/spritemodel.h @@ -1,57 +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 -*/ - -// -// Sprite Model Plugin -// -// Code by Hydra aka Dominic Clifton -// -// Based on MD3Model source code by SPoG -// - -#include "plugin.h" - -/*! i guess a description should go here... */ -class CSpriteModel: public IRender//, public ISelect -{ -public: - CSpriteModel(); - ~CSpriteModel(); - - void IncRef() { refCount++; } - void DecRef() { if(--refCount == 0) delete this; } - - //IRender - void Draw(int state, int rflags) const; - const aabb_t *GetAABB() const { return &m_BBox; } - - //ISelect - //bool TestRay (const ray_t *ray, vec_t *dist) const; - - void Construct(IShader *pShader); - -protected: - IShader *m_pShader; - -private: - int refCount; - aabb_t m_BBox; -}; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 "plugin.h" + +/*! i guess a description should go here... */ +class CSpriteModel: public IRender//, public ISelect +{ +public: + CSpriteModel(); + ~CSpriteModel(); + + void IncRef() { refCount++; } + void DecRef() { if(--refCount == 0) delete this; } + + //IRender + void Draw(int state, int rflags) const; + const aabb_t *GetAABB() const { return &m_BBox; } + + //ISelect + //bool TestRay (const ray_t *ray, vec_t *dist) const; + + void Construct(IShader *pShader); + +protected: + IShader *m_pShader; + +private: + int refCount; + aabb_t m_BBox; +}; diff --git a/plugins/surface/surfacedialog.h b/plugins/surface/surfacedialog.h index 96ab3c79..4a5b815b 100644 --- a/plugins/surface/surfacedialog.h +++ b/plugins/surface/surfacedialog.h @@ -1,31 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/surface/surfdlg_plugin.h index 89129d45..f5391344 100644 --- a/plugins/surface/surfdlg_plugin.h +++ b/plugins/surface/surfdlg_plugin.h @@ -1,94 +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_ - +/* +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/surfacedialog.h b/plugins/surface_heretic2/surfacedialog.h index 96ab3c79..4a5b815b 100644 --- a/plugins/surface_heretic2/surfacedialog.h +++ b/plugins/surface_heretic2/surfacedialog.h @@ -1,31 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h index 1b00e1a3..c074906e 100644 --- a/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h +++ b/plugins/surface_heretic2/surfaceflagsdialog_heretic2.h @@ -1,76 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/surface_heretic2/surfdlg_plugin.h index 89129d45..f5391344 100644 --- a/plugins/surface_heretic2/surfdlg_plugin.h +++ b/plugins/surface_heretic2/surfdlg_plugin.h @@ -1,94 +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_ - +/* +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/surfacedialog.h b/plugins/surface_quake2/surfacedialog.h index 96ab3c79..4a5b815b 100644 --- a/plugins/surface_quake2/surfacedialog.h +++ b/plugins/surface_quake2/surfacedialog.h @@ -1,31 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/surface_quake2/surfaceflagsdialog_quake2.h index 04e745f2..985c3708 100644 --- a/plugins/surface_quake2/surfaceflagsdialog_quake2.h +++ b/plugins/surface_quake2/surfaceflagsdialog_quake2.h @@ -1,108 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/surface_quake2/surfdlg_plugin.h index 89129d45..f5391344 100644 --- a/plugins/surface_quake2/surfdlg_plugin.h +++ b/plugins/surface_quake2/surfdlg_plugin.h @@ -1,94 +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_ - +/* +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/2DView.h b/plugins/textool/2DView.h index 4f8eac97..59163f80 100644 --- a/plugins/textool/2DView.h +++ b/plugins/textool/2DView.h @@ -1,70 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/plugins/textool/ControlPointsManager.h index 00502c37..70374005 100644 --- a/plugins/textool/ControlPointsManager.h +++ b/plugins/textool/ControlPointsManager.h @@ -1,133 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/StdAfx.h b/plugins/textool/StdAfx.h index 2a2da9c3..f54bb591 100644 --- a/plugins/textool/StdAfx.h +++ b/plugins/textool/StdAfx.h @@ -1,154 +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 <gdk/gdkkeysyms.h> -#include <gtk/gtk.h> -#include <stdio.h> -#include <stdlib.h> - -#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; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <gdk/gdkkeysyms.h> +#include <gtk/gtk.h> +#include <stdio.h> +#include <stdlib.h> + +#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/resource.h b/plugins/textool/resource.h index 22f6e86c..85ba8d7d 100644 --- a/plugins/textool/resource.h +++ b/plugins/textool/resource.h @@ -1,23 +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 +//{{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.h b/plugins/vfspak/vfs.h index a206a1fc..6e595cc9 100644 --- a/plugins/vfspak/vfs.h +++ b/plugins/vfspak/vfs.h @@ -1,52 +1,52 @@ -/* -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 (); - -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); - -void vfsFreeFile (void *p); -int vfsLoadFullPathFile (const char *filename, void **buffer); -void vfsCleanFileName(char *); -const char* vfsBasePromptPath(); -char* vfsExtractRelativePath(const char *in); -char* vfsGetFullPath(const char*, int index = 0, int flag = 0); - -#endif // _VFS_H_ +/* +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 (); + +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); + +void vfsFreeFile (void *p); +int vfsLoadFullPathFile (const char *filename, void **buffer); +void vfsCleanFileName(char *); +const char* vfsBasePromptPath(); +char* vfsExtractRelativePath(const char *in); +char* vfsGetFullPath(const char*, int index = 0, int flag = 0); + +#endif // _VFS_H_ diff --git a/plugins/vfspak/vfspak.h b/plugins/vfspak/vfspak.h index 4676ac37..2e10ca62 100644 --- a/plugins/vfspak/vfspak.h +++ b/plugins/vfspak/vfspak.h @@ -1,64 +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_ +/* +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/vfspk3/unzip-vfspk3.h b/plugins/vfspk3/unzip-vfspk3.h index 930de283..001a1f54 100644 --- a/plugins/vfspk3/unzip-vfspk3.h +++ b/plugins/vfspk3/unzip-vfspk3.h @@ -1,299 +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 -*/ +#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/vfs.h b/plugins/vfspk3/vfs.h index 8ab7cddd..bfb3479e 100644 --- a/plugins/vfspk3/vfs.h +++ b/plugins/vfspk3/vfs.h @@ -1,68 +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_ +/* +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.h b/plugins/vfspk3/vfspk3.h index 1462656f..20dc95fe 100644 --- a/plugins/vfspk3/vfspk3.h +++ b/plugins/vfspk3/vfspk3.h @@ -1,63 +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_ +/* +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/vfswad/unwad.h b/plugins/vfswad/unwad.h index e1170531..074a75ea 100644 --- a/plugins/vfswad/unwad.h +++ b/plugins/vfswad/unwad.h @@ -1,111 +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_ + +#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.h b/plugins/vfswad/vfs.h index 155e993d..ec9791f8 100644 --- a/plugins/vfswad/vfs.h +++ b/plugins/vfswad/vfs.h @@ -1,69 +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_ +/* +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.h b/plugins/vfswad/vfswad.h index 7e8cbb85..4845d591 100644 --- a/plugins/vfswad/vfswad.h +++ b/plugins/vfswad/vfswad.h @@ -1,63 +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_ +/* +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/radiant/brush.h b/radiant/brush.h index dc0a6641..08a5e057 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -1,89 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/camera.h b/radiant/camera.h index f7c90dd0..57a9fae2 100644 --- a/radiant/camera.h +++ b/radiant/camera.h @@ -1,83 +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; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/camwindow.h index 98556b00..b8d1be75 100644 --- a/radiant/camwindow.h +++ b/radiant/camwindow.h @@ -1,171 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/dialog.h b/radiant/dialog.h index f9450efe..8ca4b27d 100644 --- a/radiant/dialog.h +++ b/radiant/dialog.h @@ -1,85 +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 <gtk/gtk.h> -#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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <gtk/gtk.h> +#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/eclass_def.h b/radiant/eclass_def.h index b8738ac5..e7a6f07a 100644 --- a/radiant/eclass_def.h +++ b/radiant/eclass_def.h @@ -1,44 +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 -*/ - -/*! \file eclass_def.h - \brief the part shared between radiant core and it's builtin module eclass_def.cpp -*/ - -#ifndef _ECLASS_DEF_H_ -#define _ECLASS_DEF_H_ - -class CSynapseBuiltinClientDef : public CSynapseBuiltinClient -{ - public: - CSynapseBuiltinClientDef() {} - virtual ~CSynapseBuiltinClientDef() {} - - // CSynapseClient API - bool RequestAPI(APIDescriptor_t *pAPI); - const char* GetInfo(); - - // CSynapseBuiltinClient API - void EnumerateInterfaces(CSynapseServer *server); - -}; - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! \file eclass_def.h + \brief the part shared between radiant core and it's builtin module eclass_def.cpp +*/ + +#ifndef _ECLASS_DEF_H_ +#define _ECLASS_DEF_H_ + +class CSynapseBuiltinClientDef : public CSynapseBuiltinClient +{ + public: + CSynapseBuiltinClientDef() {} + virtual ~CSynapseBuiltinClientDef() {} + + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + // CSynapseBuiltinClient API + void EnumerateInterfaces(CSynapseServer *server); + +}; + +#endif diff --git a/radiant/feedback.h b/radiant/feedback.h index 687fe94b..6fb93b6a 100644 --- a/radiant/feedback.h +++ b/radiant/feedback.h @@ -1,125 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/file.h index d9f1bd7e..03ec33fc 100644 --- a/radiant/file.h +++ b/radiant/file.h @@ -1,119 +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 <stdio.h> - -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_ +/* +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 <stdio.h> + +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.h b/radiant/filters.h index 5f467f1d..b09d36f3 100644 --- a/radiant/filters.h +++ b/radiant/filters.h @@ -1,30 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/findtexturedialog.h index 96060ea2..eb1e61e1 100644 --- a/radiant/findtexturedialog.h +++ b/radiant/findtexturedialog.h @@ -1,49 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/glwidget.h b/radiant/glwidget.h index 1ce7f140..582a5ddb 100644 --- a/radiant/glwidget.h +++ b/radiant/glwidget.h @@ -1,45 +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_ */ +/* +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.h b/radiant/glwindow.h index 209b94d3..a6bac087 100644 --- a/radiant/glwindow.h +++ b/radiant/glwindow.h @@ -1,108 +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_ +/* +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.h b/radiant/groupdialog.h index a2531071..33e3640c 100644 --- a/radiant/groupdialog.h +++ b/radiant/groupdialog.h @@ -1,108 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/gtkfilesel-darwin.c b/radiant/gtkfilesel-darwin.c index 2076423c..65c8bd0d 100644 --- a/radiant/gtkfilesel-darwin.c +++ b/radiant/gtkfilesel-darwin.c @@ -1,3360 +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 <torriem@byu.edu> -// http://students.cs.byu.edu/~torriem/gtk/ - -// common files win32/linux -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> - -// TTimo -// NOTE: the mkdir stuff etc. is in <direct.h> .. but I don't know what's the best strategy yet. -// just including <direct.h> here doesn't cut it - -#if defined (__linux__) || (__APPLE__) -#include <sys/param.h> -#include <dirent.h> -#include <unistd.h> -#include <pwd.h> -#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; i<n_no_stat_dirs; i++) - { - if (no_stat_dirs[i].present && - (no_stat_dirs[i].statbuf.st_dev == result->st_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 +/* 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 <torriem@byu.edu> +// http://students.cs.byu.edu/~torriem/gtk/ + +// common files win32/linux +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +// TTimo +// NOTE: the mkdir stuff etc. is in <direct.h> .. but I don't know what's the best strategy yet. +// just including <direct.h> here doesn't cut it + +#if defined (__linux__) || (__APPLE__) +#include <sys/param.h> +#include <dirent.h> +#include <unistd.h> +#include <pwd.h> +#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; i<n_no_stat_dirs; i++) + { + if (no_stat_dirs[i].present && + (no_stat_dirs[i].statbuf.st_dev == result->st_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 index e264e1b2..135a1fa5 100644 --- a/radiant/gtkfilesel-darwin.h +++ b/radiant/gtkfilesel-darwin.h @@ -1,129 +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 <gdk/gdk.h> -#include <gtk/gtkwindow.h> - - -#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__ */ - - - - - - - - - - +/* 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 <gdk/gdk.h> +#include <gtk/gtkwindow.h> + + +#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 index 58af1801..16fe0b56 100644 --- a/radiant/gtkfilesel-linux.c +++ b/radiant/gtkfilesel-linux.c @@ -1,4987 +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 <fcntl.h> -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <dirent.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <pwd.h> -#include <grp.h> -#include <time.h> - -#include "fnmatch.h" - -#if (defined TORRIE_DEBUG || defined LEO) -#include <gdk/gdkkeysyms.h> -#include <gtk/gtkbutton.h> -#include <gtk/gtkentry.h> -#include "gtkfilesel-linux.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> -#include <gtk/gtkhpaned.h> -#include <gtk/gtktable.h> -#include <gtk/gtkpixmap.h> -#include <gtk/gtknotebook.h> -#include <gtk/gtkhseparator.h> -#include <gtk/gtktogglebutton.h> -#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; i<n_no_stat_dirs; i++) - { - if (no_stat_dirs[i].present && - (no_stat_dirs[i].statbuf.st_dev == result->st_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 +/* 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 <fcntl.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <dirent.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#include <grp.h> +#include <time.h> + +#include "fnmatch.h" + +#if (defined TORRIE_DEBUG || defined LEO) +#include <gdk/gdkkeysyms.h> +#include <gtk/gtkbutton.h> +#include <gtk/gtkentry.h> +#include "gtkfilesel-linux.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> +#include <gtk/gtkhpaned.h> +#include <gtk/gtktable.h> +#include <gtk/gtkpixmap.h> +#include <gtk/gtknotebook.h> +#include <gtk/gtkhseparator.h> +#include <gtk/gtktogglebutton.h> +#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; i<n_no_stat_dirs; i++) + { + if (no_stat_dirs[i].present && + (no_stat_dirs[i].statbuf.st_dev == result->st_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 index 5fb1c29e..b9ab49b7 100644 --- a/radiant/gtkfilesel-linux.h +++ b/radiant/gtkfilesel-linux.h @@ -1,143 +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 <gdk/gdk.h> -#include <gtk/gtkwindow.h> - - -#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 <MASK>" or simply "MASK" - ie: "C,C++ files <*.[Cc],*.cc,*.cpp>" or simply - "*.jpg,*.gif" etc - -*/ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __GTK_FILESEL_H__ */ - - - - - - - - - - +/* 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 <gdk/gdk.h> +#include <gtk/gtkwindow.h> + + +#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 <MASK>" 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 index 58fde0bb..aacc3b99 100644 --- a/radiant/gtkfilesel.c +++ b/radiant/gtkfilesel.c @@ -1,3337 +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 <torriem@byu.edu> -// http://students.cs.byu.edu/~torriem/gtk/ - -#include <stdio.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/param.h> -#include <dirent.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <pwd.h> -#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; i<n_no_stat_dirs; i++) - { - if (no_stat_dirs[i].present && - (no_stat_dirs[i].statbuf.st_dev == result->st_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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <torriem@byu.edu> +// http://students.cs.byu.edu/~torriem/gtk/ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <dirent.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <pwd.h> +#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; i<n_no_stat_dirs; i++) + { + if (no_stat_dirs[i].present && + (no_stat_dirs[i].statbuf.st_dev == result->st_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 index b5c2a697..098cf27d 100644 --- a/radiant/gtkfilesel.h +++ b/radiant/gtkfilesel.h @@ -1,143 +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 <gdk/gdk.h> -#include <gtk/gtkwindow.h> - - -#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__ */ - - - - - - - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <gdk/gdk.h> +#include <gtk/gtkwindow.h> + + +#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.h b/radiant/gtkmisc.h index ee6bc5fd..c8446d6f 100644 --- a/radiant/gtkmisc.h +++ b/radiant/gtkmisc.h @@ -1,100 +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_ +/* +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/mainframe.h b/radiant/mainframe.h index 7b2cb63f..23a42642 100644 --- a/radiant/mainframe.h +++ b/radiant/mainframe.h @@ -1,909 +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<Str *> 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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<Str *> 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.h b/radiant/map.h index efc8f68a..39b96ff5 100644 --- a/radiant/map.h +++ b/radiant/map.h @@ -1,72 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/parse.h b/radiant/parse.h index de679de2..ce9e55ba 100644 --- a/radiant/parse.h +++ b/radiant/parse.h @@ -1,35 +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() - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/patchdialog.h index 04c4f6b6..7316b88c 100644 --- a/radiant/patchdialog.h +++ b/radiant/patchdialog.h @@ -1,85 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 9c903891..060ddb56 100644 --- a/radiant/plugin.h +++ b/radiant/plugin.h @@ -1,45 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/pluginmanager.h b/radiant/pluginmanager.h index fe096e77..96e2ac98 100644 --- a/radiant/pluginmanager.h +++ b/radiant/pluginmanager.h @@ -1,212 +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<CPluginSlot *> 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<CImageTableSlot *> mSlots; - - list<CImageTableSlot *>::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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<CPluginSlot *> 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<CImageTableSlot *> mSlots; + + list<CImageTableSlot *>::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/points.h b/radiant/points.h index bc44cb8a..cb7641c7 100644 --- a/radiant/points.h +++ b/radiant/points.h @@ -1,57 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/preferences.h index 7abd86eb..581c8fe7 100644 --- a/radiant/preferences.h +++ b/radiant/preferences.h @@ -1,628 +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<CPrefAssignment> 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<CGameDescription *> 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<CGameDescription *> 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/<version>/ - */ - GString *m_global_rc_path; - - /*! - path to per-game settings - used for various game dependant storage - win32: g_strGameToolsPath - linux: ~/.radiant/<version>/<gamename>/ - */ - 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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<CPrefAssignment> 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<CGameDescription *> 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<CGameDescription *> 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/<version>/ + */ + GString *m_global_rc_path; + + /*! + path to per-game settings + used for various game dependant storage + win32: g_strGameToolsPath + linux: ~/.radiant/<version>/<gamename>/ + */ + 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/qe3.h b/radiant/qe3.h index 5f8c815d..e1b9d2bc 100644 --- a/radiant/qe3.h +++ b/radiant/qe3.h @@ -1,912 +1,912 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 _QE3_H_ -#define _QE3_H_ - -#ifdef _WIN32 - -// disable data conversion warnings for gl -#pragma warning(disable : 4244) // MIPS -#pragma warning(disable : 4136) // X86 -#pragma warning(disable : 4051) // ALPHA -#pragma warning(disable : 4800) -#endif - -// for interfaces, we require main plugin header included -#include "iplugin.h" -#include "qerplugin.h" -#include "qertypes.h" - -#include "missing.h" // temporary stuff, needs to be removed -#include "idatastream.h" -#include "file.h" - -#include "qgl.h" - -#include <gtk/gtk.h> -#include <math.h> -#include <stdlib.h> - -#include <stdio.h> - -// 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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 _QE3_H_ +#define _QE3_H_ + +#ifdef _WIN32 + +// disable data conversion warnings for gl +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA +#pragma warning(disable : 4800) +#endif + +// for interfaces, we require main plugin header included +#include "iplugin.h" +#include "qerplugin.h" +#include "qertypes.h" + +#include "missing.h" // temporary stuff, needs to be removed +#include "idatastream.h" +#include "file.h" + +#include "qgl.h" + +#include <gtk/gtk.h> +#include <math.h> +#include <stdlib.h> + +#include <stdio.h> + +// 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 index 463fcc29..23a3d28b 100644 --- a/radiant/qedefs.h +++ b/radiant/qedefs.h @@ -1,128 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index b339d3d1..c602ec84 100644 --- a/radiant/qfiles.h +++ b/radiant/qfiles.h @@ -1,480 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 5b769090..105f21e3 100644 --- a/radiant/qgl-mac.c +++ b/radiant/qgl-mac.c @@ -1,1775 +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 <stdio.h> -#include <float.h> -#include <string.h> -#if defined (__linux__) || defined (__APPLE__) -//#include <dlfcn.h> -#endif -#ifdef _WIN32 -#include <windows.h> -#endif -#include "qgl.h" -#include <GL/glu.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); -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 <math.h> -#include <stdlib.h> -#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"); - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <float.h> +#include <string.h> +#if defined (__linux__) || defined (__APPLE__) +//#include <dlfcn.h> +#endif +#ifdef _WIN32 +#include <windows.h> +#endif +#include "qgl.h" +#include <GL/glu.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); +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 <math.h> +#include <stdlib.h> +#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 index 6fb4eb5d..d7fd7ce9 100644 --- a/radiant/qgl.c +++ b/radiant/qgl.c @@ -1,1797 +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 <stdio.h> -#include <float.h> -#include <string.h> -#if defined (__linux__) || defined (__APPLE__) -#include <dlfcn.h> -#endif - -#ifdef _WIN32 -#include <windows.h> -#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 <math.h> -#include <stdlib.h> -#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"); - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <float.h> +#include <string.h> +#if defined (__linux__) || defined (__APPLE__) +#include <dlfcn.h> +#endif + +#ifdef _WIN32 +#include <windows.h> +#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 <math.h> +#include <stdlib.h> +#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 index 6f4decc6..faccdb2f 100644 --- a/radiant/qgl.h +++ b/radiant/qgl.h @@ -1,600 +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 <GL/gl.h> - -#if defined (__linux__) || defined (__APPLE__) -#include <GL/glx.h> -#endif - -#if defined (__APPLE__) -#include <GL/glu.h> -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <GL/gl.h> + +#if defined (__linux__) || defined (__APPLE__) +#include <GL/glx.h> +#endif + +#if defined (__APPLE__) +#include <GL/glu.h> +#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/resource.h b/radiant/resource.h index 770c06b9..17099dac 100644 --- a/radiant/resource.h +++ b/radiant/resource.h @@ -1,37 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/select.h index 8bcafff1..42718162 100644 --- a/radiant/select.h +++ b/radiant/select.h @@ -1,82 +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(); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/stdafx.h b/radiant/stdafx.h index cb6c327f..85d83e1c 100644 --- a/radiant/stdafx.h +++ b/radiant/stdafx.h @@ -1,39 +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 <windows.h> -#endif -#include "qe3.h" +/* +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 <windows.h> +#endif +#include "qe3.h" diff --git a/radiant/surfacedialog.h b/radiant/surfacedialog.h index 6d5d48a1..71741b9e 100644 --- a/radiant/surfacedialog.h +++ b/radiant/surfacedialog.h @@ -1,69 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/surfaceplugin.h index 6f08c227..4e32e92f 100644 --- a/radiant/surfaceplugin.h +++ b/radiant/surfaceplugin.h @@ -1,11 +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 +#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/texmanip.h b/radiant/texmanip.h index f3e0b5c3..07548700 100644 --- a/radiant/texmanip.h +++ b/radiant/texmanip.h @@ -1,39 +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_ +/* +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 index 571319a4..2261053a 100644 --- a/radiant/textures.h +++ b/radiant/textures.h @@ -1,52 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/texwindow.h index 7f6e9260..f0f03daf 100644 --- a/radiant/texwindow.h +++ b/radiant/texwindow.h @@ -1,62 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/ui.h index 135ed93e..7bc99c94 100644 --- a/radiant/ui.h +++ b/radiant/ui.h @@ -1,84 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/undo.h index 21ec93f4..5973202a 100644 --- a/radiant/undo.h +++ b/radiant/undo.h @@ -1,66 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/watchbsp.h b/radiant/watchbsp.h index c124c54f..dcf7dea5 100644 --- a/radiant/watchbsp.h +++ b/radiant/watchbsp.h @@ -1,91 +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 +/* +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.h b/radiant/winding.h index 3f21a204..426cad9b 100644 --- a/radiant/winding.h +++ b/radiant/winding.h @@ -1,70 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index dc23f644..7d69c169 100644 --- a/radiant/xmlstuff.h +++ b/radiant/xmlstuff.h @@ -1,70 +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 +/* +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.h b/radiant/xywindow.h index a81acadd..23aec2c4 100644 --- a/radiant/xywindow.h +++ b/radiant/xywindow.h @@ -1,194 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/z.h index acf12a89..aee8bae2 100644 --- a/radiant/z.h +++ b/radiant/z.h @@ -1,42 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.h b/radiant/zwindow.h index d1f42bbd..90f3954b 100644 --- a/radiant/zwindow.h +++ b/radiant/zwindow.h @@ -1,46 +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_ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/tools/quake2/common/bspfile.c b/tools/quake2/common/bspfile.c index eac27aff..df3f059b 100644 --- a/tools/quake2/common/bspfile.c +++ b/tools/quake2/common/bspfile.c @@ -1,789 +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<visrow ; j++) - { - *dest_p++ = vis[j]; - if (vis[j]) - continue; - - rep = 1; - for ( j++; j<visrow ; j++) - if (vis[j] || rep == 255) - break; - else - rep++; - *dest_p++ = rep; - j--; - } - - return dest_p - dest; -} - - -/* -=================== -DecompressVis -=================== -*/ -void DecompressVis (byte *in, byte *decompressed) -{ - int c; - byte *out; - int row; - -// row = (r_numvisleafs+7)>>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 ; i<nummodels ; i++) - { - d = &dmodels[i]; - - d->firstface = 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 ; i<numvertexes ; i++) - { - for (j=0 ; j<3 ; j++) - dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]); - } - -// -// planes -// - for (i=0 ; i<numplanes ; i++) - { - for (j=0 ; j<3 ; j++) - dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]); - dplanes[i].dist = LittleFloat (dplanes[i].dist); - dplanes[i].type = LittleLong (dplanes[i].type); - } - -// -// texinfos -// - for (i=0 ; i<numtexinfo ; i++) - { - for (j=0 ; j<8 ; j++) - texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]); - texinfo[i].flags = LittleLong (texinfo[i].flags); - texinfo[i].value = LittleLong (texinfo[i].value); - texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo); - } - -// -// faces -// - for (i=0 ; i<numfaces ; i++) - { - dfaces[i].texinfo = LittleShort (dfaces[i].texinfo); - dfaces[i].planenum = LittleShort (dfaces[i].planenum); - dfaces[i].side = LittleShort (dfaces[i].side); - dfaces[i].lightofs = LittleLong (dfaces[i].lightofs); - dfaces[i].firstedge = LittleLong (dfaces[i].firstedge); - dfaces[i].numedges = LittleShort (dfaces[i].numedges); - } - -// -// nodes -// - for (i=0 ; i<numnodes ; i++) - { - dnodes[i].planenum = LittleLong (dnodes[i].planenum); - for (j=0 ; j<3 ; j++) - { - dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]); - dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]); - } - dnodes[i].children[0] = LittleLong (dnodes[i].children[0]); - dnodes[i].children[1] = LittleLong (dnodes[i].children[1]); - dnodes[i].firstface = LittleShort (dnodes[i].firstface); - dnodes[i].numfaces = LittleShort (dnodes[i].numfaces); - } - -// -// leafs -// - for (i=0 ; i<numleafs ; i++) - { - dleafs[i].contents = LittleLong (dleafs[i].contents); - dleafs[i].cluster = LittleShort (dleafs[i].cluster); - dleafs[i].area = LittleShort (dleafs[i].area); - for (j=0 ; j<3 ; j++) - { - dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]); - dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]); - } - - dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface); - dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces); - dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush); - dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes); - } - -// -// leaffaces -// - for (i=0 ; i<numleaffaces ; i++) - dleaffaces[i] = LittleShort (dleaffaces[i]); - -// -// leafbrushes -// - for (i=0 ; i<numleafbrushes ; i++) - dleafbrushes[i] = LittleShort (dleafbrushes[i]); - -// -// surfedges -// - for (i=0 ; i<numsurfedges ; i++) - dsurfedges[i] = LittleLong (dsurfedges[i]); - -// -// edges -// - for (i=0 ; i<numedges ; i++) - { - dedges[i].v[0] = LittleShort (dedges[i].v[0]); - dedges[i].v[1] = LittleShort (dedges[i].v[1]); - } - -// -// brushes -// - for (i=0 ; i<numbrushes ; i++) - { - dbrushes[i].firstside = LittleLong (dbrushes[i].firstside); - dbrushes[i].numsides = LittleLong (dbrushes[i].numsides); - dbrushes[i].contents = LittleLong (dbrushes[i].contents); - } - -// -// areas -// - for (i=0 ; i<numareas ; i++) - { - dareas[i].numareaportals = LittleLong (dareas[i].numareaportals); - dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal); - } - -// -// areasportals -// - for (i=0 ; i<numareaportals ; i++) - { - dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum); - dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea); - } - -// -// brushsides -// - for (i=0 ; i<numbrushsides ; i++) - { - dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum); - dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo); - } - -// -// visibility -// - if (todisk) - j = dvis->numclusters; - else - j = LittleLong(dvis->numclusters); - dvis->numclusters = LittleLong (dvis->numclusters); - for (i=0 ; i<j ; i++) - { - dvis->bitofs[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 ; i<num_entities ; i++) - { - ep = entities[i].epairs; - if (!ep) - continue; // ent got removed - - strcat (end,"{\n"); - end += 2; - - for (ep = entities[i].epairs ; ep ; ep=ep->next) - { - 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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<visrow ; j++) + { + *dest_p++ = vis[j]; + if (vis[j]) + continue; + + rep = 1; + for ( j++; j<visrow ; j++) + if (vis[j] || rep == 255) + break; + else + rep++; + *dest_p++ = rep; + j--; + } + + return dest_p - dest; +} + + +/* +=================== +DecompressVis +=================== +*/ +void DecompressVis (byte *in, byte *decompressed) +{ + int c; + byte *out; + int row; + +// row = (r_numvisleafs+7)>>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 ; i<nummodels ; i++) + { + d = &dmodels[i]; + + d->firstface = 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 ; i<numvertexes ; i++) + { + for (j=0 ; j<3 ; j++) + dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]); + } + +// +// planes +// + for (i=0 ; i<numplanes ; i++) + { + for (j=0 ; j<3 ; j++) + dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]); + dplanes[i].dist = LittleFloat (dplanes[i].dist); + dplanes[i].type = LittleLong (dplanes[i].type); + } + +// +// texinfos +// + for (i=0 ; i<numtexinfo ; i++) + { + for (j=0 ; j<8 ; j++) + texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]); + texinfo[i].flags = LittleLong (texinfo[i].flags); + texinfo[i].value = LittleLong (texinfo[i].value); + texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo); + } + +// +// faces +// + for (i=0 ; i<numfaces ; i++) + { + dfaces[i].texinfo = LittleShort (dfaces[i].texinfo); + dfaces[i].planenum = LittleShort (dfaces[i].planenum); + dfaces[i].side = LittleShort (dfaces[i].side); + dfaces[i].lightofs = LittleLong (dfaces[i].lightofs); + dfaces[i].firstedge = LittleLong (dfaces[i].firstedge); + dfaces[i].numedges = LittleShort (dfaces[i].numedges); + } + +// +// nodes +// + for (i=0 ; i<numnodes ; i++) + { + dnodes[i].planenum = LittleLong (dnodes[i].planenum); + for (j=0 ; j<3 ; j++) + { + dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]); + dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]); + } + dnodes[i].children[0] = LittleLong (dnodes[i].children[0]); + dnodes[i].children[1] = LittleLong (dnodes[i].children[1]); + dnodes[i].firstface = LittleShort (dnodes[i].firstface); + dnodes[i].numfaces = LittleShort (dnodes[i].numfaces); + } + +// +// leafs +// + for (i=0 ; i<numleafs ; i++) + { + dleafs[i].contents = LittleLong (dleafs[i].contents); + dleafs[i].cluster = LittleShort (dleafs[i].cluster); + dleafs[i].area = LittleShort (dleafs[i].area); + for (j=0 ; j<3 ; j++) + { + dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]); + dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]); + } + + dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface); + dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces); + dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush); + dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes); + } + +// +// leaffaces +// + for (i=0 ; i<numleaffaces ; i++) + dleaffaces[i] = LittleShort (dleaffaces[i]); + +// +// leafbrushes +// + for (i=0 ; i<numleafbrushes ; i++) + dleafbrushes[i] = LittleShort (dleafbrushes[i]); + +// +// surfedges +// + for (i=0 ; i<numsurfedges ; i++) + dsurfedges[i] = LittleLong (dsurfedges[i]); + +// +// edges +// + for (i=0 ; i<numedges ; i++) + { + dedges[i].v[0] = LittleShort (dedges[i].v[0]); + dedges[i].v[1] = LittleShort (dedges[i].v[1]); + } + +// +// brushes +// + for (i=0 ; i<numbrushes ; i++) + { + dbrushes[i].firstside = LittleLong (dbrushes[i].firstside); + dbrushes[i].numsides = LittleLong (dbrushes[i].numsides); + dbrushes[i].contents = LittleLong (dbrushes[i].contents); + } + +// +// areas +// + for (i=0 ; i<numareas ; i++) + { + dareas[i].numareaportals = LittleLong (dareas[i].numareaportals); + dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal); + } + +// +// areasportals +// + for (i=0 ; i<numareaportals ; i++) + { + dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum); + dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea); + } + +// +// brushsides +// + for (i=0 ; i<numbrushsides ; i++) + { + dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum); + dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo); + } + +// +// visibility +// + if (todisk) + j = dvis->numclusters; + else + j = LittleLong(dvis->numclusters); + dvis->numclusters = LittleLong (dvis->numclusters); + for (i=0 ; i<j ; i++) + { + dvis->bitofs[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 ; i<num_entities ; i++) + { + ep = entities[i].epairs; + if (!ep) + continue; // ent got removed + + strcat (end,"{\n"); + end += 2; + + for (ep = entities[i].epairs ; ep ; ep=ep->next) + { + 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 index b4d6b355..f25329fb 100644 --- a/tools/quake2/common/bspfile.h +++ b/tools/quake2/common/bspfile.h @@ -1,128 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 6a005e32..68a16d82 100644 --- a/tools/quake2/common/cmdlib.c +++ b/tools/quake2/common/cmdlib.c @@ -1,1221 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#endif - -#if defined (__linux__) || defined (__APPLE__) -#include <unistd.h> -#endif - -#ifdef NeXT -#include <libc.h> -#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<myargc;i++) - { - if ( !Q_stricmp(check, myargv[i]) ) - return i; - } - - return 0; -} - - - -/* -================ -Q_filelength -================ -*/ -int Q_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; -} - - -FILE *SafeOpenWrite (const char *filename) -{ - FILE *f; - - f = fopen(filename, "wb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - -FILE *SafeOpenRead (const char *filename) -{ - FILE *f; - - f = fopen(filename, "rb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - - -void SafeRead (FILE *f, void *buffer, int count) -{ - if ( fread (buffer, 1, count, f) != (size_t)count) - Error ("File read failure"); -} - - -void SafeWrite (FILE *f, const void *buffer, int count) -{ - if (fwrite (buffer, 1, count, f) != (size_t)count) - Error ("File write failure"); -} - - -/* -============== -FileExists -============== -*/ -qboolean FileExists (const char *filename) -{ - FILE *f; - - f = fopen (filename, "r"); - if (!f) - return false; - fclose (f); - return true; -} - -/* -============== -LoadFile -============== -*/ -int LoadFile( const char *filename, void **bufferptr ) -{ - FILE *f; - int length; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - buffer = safe_malloc (length+1); - ((char *)buffer)[length] = 0; - SafeRead (f, buffer, length); - fclose (f); - - *bufferptr = buffer; - return length; -} - - -/* -============== -LoadFileBlock -- -rounds up memory allocation to 4K boundry -- -============== -*/ -int LoadFileBlock( const char *filename, void **bufferptr ) -{ - FILE *f; - int length, nBlock, nAllocSize; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - nAllocSize = length; - nBlock = nAllocSize % MEM_BLOCKSIZE; - if ( nBlock > 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 -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include <unistd.h> +#endif + +#ifdef NeXT +#include <libc.h> +#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<myargc;i++) + { + if ( !Q_stricmp(check, myargv[i]) ) + return i; + } + + return 0; +} + + + +/* +================ +Q_filelength +================ +*/ +int Q_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; +} + + +FILE *SafeOpenWrite (const char *filename) +{ + FILE *f; + + f = fopen(filename, "wb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + +FILE *SafeOpenRead (const char *filename) +{ + FILE *f; + + f = fopen(filename, "rb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + + +void SafeRead (FILE *f, void *buffer, int count) +{ + if ( fread (buffer, 1, count, f) != (size_t)count) + Error ("File read failure"); +} + + +void SafeWrite (FILE *f, const void *buffer, int count) +{ + if (fwrite (buffer, 1, count, f) != (size_t)count) + Error ("File write failure"); +} + + +/* +============== +FileExists +============== +*/ +qboolean FileExists (const char *filename) +{ + FILE *f; + + f = fopen (filename, "r"); + if (!f) + return false; + fclose (f); + return true; +} + +/* +============== +LoadFile +============== +*/ +int LoadFile( const char *filename, void **bufferptr ) +{ + FILE *f; + int length; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +LoadFileBlock +- +rounds up memory allocation to 4K boundry +- +============== +*/ +int LoadFileBlock( const char *filename, void **bufferptr ) +{ + FILE *f; + int length, nBlock, nAllocSize; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + nAllocSize = length; + nBlock = nAllocSize % MEM_BLOCKSIZE; + if ( nBlock > 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 index c3a5698f..02ced5be 100644 --- a/tools/quake2/common/cmdlib.h +++ b/tools/quake2/common/cmdlib.h @@ -1,170 +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 <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <time.h> -#include <stdarg.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 - -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <stdarg.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 + +#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 index ef21edea..33eac651 100644 --- a/tools/quake2/common/inout.c +++ b/tools/quake2/common/inout.c @@ -1,367 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); - 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 level='flag'> - message string - .. various nodes to describe corresponding geometry .. - </message> - */ - 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); + 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 level='flag'> + message string + .. various nodes to describe corresponding geometry .. + </message> + */ + 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 index 4843a7b6..05b56a09 100644 --- a/tools/quake2/common/inout.h +++ b/tools/quake2/common/inout.h @@ -1,63 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 7a551b11..e9b25681 100644 --- a/tools/quake2/common/l3dslib.c +++ b/tools/quake2/common/l3dslib.c @@ -1,300 +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 <stdio.h> -#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<numtris ; i++) - { - for (j=0 ; j<3 ; j++) - { - for (k=0 ; k<3 ; k++) - { - ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; - } - } - } - - totaltris += numtris; - numtris = 0; - vertsfound = 0; - trisfound = 0; -} - - -int ParseVertexL (FILE *input) -{ - int i, j, startbytesread, numverts; - unsigned short tshort; - - if (vertsfound) - Error ("Error: Multiple vertex chunks"); - - vertsfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numverts = (int)tshort; - - if (numverts > MAXVERTS) - Error ("Error: Too many vertices"); - - for (i=0 ; i<numverts ; i++) - { - for (j=0 ; j<3 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&fverts[i][j], sizeof(float), 1, input); - bytesread += sizeof(float); - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseFaceL1 (FILE *input) -{ - - int i, j, startbytesread; - unsigned short tshort; - - if (trisfound) - Error ("Error: Multiple face chunks"); - - trisfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numtris = (int)tshort; - - if (numtris > MAXTRIANGLES) - Error ("Error: Too many triangles"); - - for (i=0 ; i<numtris ; i++) - { - for (j=0 ; j<4 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - tris[i].v[j] = (int)tshort; - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseChunk (FILE *input) -{ -#define BLOCK_SIZE 4096 - char temp[BLOCK_SIZE]; - unsigned short type; - int i, length, w, t, retval; - - level++; - retval = 0; - -// chunk type - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&type, sizeof(type), 1, input); - bytesread += sizeof(type); - -// chunk length - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&length, sizeof(length), 1, input); - bytesread += sizeof(length); - w = length - 6; - -// process chunk if we care about it, otherwise skip it - switch (type) - { - case TRI_VERTEXL: - w -= ParseVertexL (input); - goto ParseSubchunk; - - case TRI_FACEL1: - w -= ParseFaceL1 (input); - goto ParseSubchunk; - - case EDIT_OBJECT: - // read the name - i = 0; - - do - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&temp[i], 1, 1, input); - i++; - w--; - bytesread++; - } while (temp[i-1]); - - case MAIN3DS: - case OBJ_TRIMESH: - case EDIT3DS: - // parse through subchunks -ParseSubchunk: - while (w > 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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<numtris ; i++) + { + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; + } + } + } + + totaltris += numtris; + numtris = 0; + vertsfound = 0; + trisfound = 0; +} + + +int ParseVertexL (FILE *input) +{ + int i, j, startbytesread, numverts; + unsigned short tshort; + + if (vertsfound) + Error ("Error: Multiple vertex chunks"); + + vertsfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numverts = (int)tshort; + + if (numverts > MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i<numverts ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&fverts[i][j], sizeof(float), 1, input); + bytesread += sizeof(float); + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseFaceL1 (FILE *input) +{ + + int i, j, startbytesread; + unsigned short tshort; + + if (trisfound) + Error ("Error: Multiple face chunks"); + + trisfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numtris = (int)tshort; + + if (numtris > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i<numtris ; i++) + { + for (j=0 ; j<4 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + tris[i].v[j] = (int)tshort; + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseChunk (FILE *input) +{ +#define BLOCK_SIZE 4096 + char temp[BLOCK_SIZE]; + unsigned short type; + int i, length, w, t, retval; + + level++; + retval = 0; + +// chunk type + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&type, sizeof(type), 1, input); + bytesread += sizeof(type); + +// chunk length + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&length, sizeof(length), 1, input); + bytesread += sizeof(length); + w = length - 6; + +// process chunk if we care about it, otherwise skip it + switch (type) + { + case TRI_VERTEXL: + w -= ParseVertexL (input); + goto ParseSubchunk; + + case TRI_FACEL1: + w -= ParseFaceL1 (input); + goto ParseSubchunk; + + case EDIT_OBJECT: + // read the name + i = 0; + + do + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp[i], 1, 1, input); + i++; + w--; + bytesread++; + } while (temp[i-1]); + + case MAIN3DS: + case OBJ_TRIMESH: + case EDIT3DS: + // parse through subchunks +ParseSubchunk: + while (w > 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 index 528adc1d..bb2c4991 100644 --- a/tools/quake2/common/l3dslib.h +++ b/tools/quake2/common/l3dslib.h @@ -1,25 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e157b94c..5039dab6 100644 --- a/tools/quake2/common/lbmlib.c +++ b/tools/quake2/common/lbmlib.c @@ -1,837 +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 (count<bpwidth); - - if (count>bpwidth) - 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) - { - if (bmhd.compression == cm_rle1) - body_p = LBMRLEDecompress ((byte *)body_p - , pic_p , bmhd.w); - else if (bmhd.compression == cm_none) - { - memcpy (pic_p,body_p,bmhd.w); - body_p += Align(bmhd.w); - } - } - - } - else - { - // - // unpack ILBM - // - Error ("%s is an interlaced LBM, not packed", filename); - } - break; - } - - LBM_P += Align(chunklength); - } - - free (LBMbuffer); - - *picture = picbuffer; - - if (palette) - *palette = cmapbuffer; -} - - -/* -============================================================================ - - WRITE LBM - -============================================================================ -*/ - -/* -============== -WriteLBMfile -============== -*/ -void WriteLBMfile (char *filename, byte *data, - int width, int height, byte *palette) -{ - byte *lbm, *lbmptr; - int *formlength, *bmhdlength, *cmaplength, *bodylength; - int length; - bmhd_t basebmhd; - - lbm = lbmptr = malloc (width*height+1000); - -// -// start FORM -// - *lbmptr++ = 'F'; - *lbmptr++ = 'O'; - *lbmptr++ = 'R'; - *lbmptr++ = 'M'; - - formlength = (int*)lbmptr; - lbmptr+=4; // leave space for length - - *lbmptr++ = 'P'; - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = ' '; - -// -// write BMHD -// - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = 'H'; - *lbmptr++ = 'D'; - - bmhdlength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memset (&basebmhd,0,sizeof(basebmhd)); - basebmhd.w = BigShort((short)width); - basebmhd.h = BigShort((short)height); - basebmhd.nPlanes = BigShort(8); - basebmhd.xAspect = BigShort(5); - basebmhd.yAspect = BigShort(6); - basebmhd.pageWidth = BigShort((short)width); - basebmhd.pageHeight = BigShort((short)height); - - memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); - lbmptr += sizeof(basebmhd); - - length = lbmptr-(byte *)bmhdlength-4; - *bmhdlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write CMAP -// - *lbmptr++ = 'C'; - *lbmptr++ = 'M'; - *lbmptr++ = 'A'; - *lbmptr++ = 'P'; - - cmaplength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,palette,768); - lbmptr += 768; - - length = lbmptr-(byte *)cmaplength-4; - *cmaplength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write BODY -// - *lbmptr++ = 'B'; - *lbmptr++ = 'O'; - *lbmptr++ = 'D'; - *lbmptr++ = 'Y'; - - bodylength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,data,width*height); - lbmptr += width*height; - - length = lbmptr-(byte *)bodylength-4; - *bodylength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// done -// - length = lbmptr-(byte *)formlength-4; - *formlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write output file -// - SaveFile (filename, lbm, lbmptr-lbm); - free (lbm); -} - - -/* -============================================================================ - -LOAD PCX - -============================================================================ -*/ - -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; - - -/* -============== -LoadPCX -============== -*/ -void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) -{ - byte *raw; - pcx_t *pcx; - int x, y; - int len; - int dataByte, runLength; - byte *out, *pix; - - // - // load the file - // - len = LoadFile (filename, (void **)&raw); - - // - // parse the PCX file - // - pcx = (pcx_t *)raw; - raw = &pcx->data; - - 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<height ; i++) - { - for (j=0 ; j<width ; j++) - { - if ( (*data & 0xc0) != 0xc0) - *pack++ = *data++; - else - { - *pack++ = 0xc1; - *pack++ = *data++; - } - } - } - - // write the palette - *pack++ = 0x0c; // palette ID byte - for (i=0 ; i<768 ; i++) - *pack++ = *palette++; - -// write output file - length = pack - (byte *)pcx; - SaveFile (filename, pcx, length); - - free (pcx); -} - - -/* -============================================================================ - -LOAD IMAGE - -============================================================================ -*/ - -/* -============== -Load256Image - -Will load either an lbm or pcx, depending on extension. -Any of the return pointers can be NULL if you don't want them. -============== -*/ -void Load256Image (char *name, byte **pixels, byte **palette, - int *width, int *height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_strncasecmp (ext, "lbm", strlen(ext) )) - { - LoadLBM (name, pixels, palette); - if (width) - *width = bmhd.w; - if (height) - *height = bmhd.h; - } - else if (!Q_strncasecmp (ext, "pcx",strlen(ext))) - { - LoadPCX (name, pixels, palette, width, height); - } - else - Error ("%s doesn't have a known image extension", name); -} - - -/* -============== -Save256Image - -Will save either an lbm or pcx, depending on extension. -============== -*/ -void Save256Image (char *name, byte *pixels, byte *palette, - int width, int height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_strncasecmp (ext, "lbm",strlen(ext))) - { - WriteLBMfile (name, pixels, width, height, palette); - } - else if (!Q_strncasecmp (ext, "pcx",strlen(ext))) - { - WritePCXfile (name, pixels, width, height, palette); - } - else - Error ("%s doesn't have a known image extension", name); -} - - - - -/* -============================================================================ - -TARGA IMAGE - -============================================================================ -*/ - -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; - -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); -} - - -/* -============= -LoadTGA -============= -*/ -void LoadTGA (char *name, byte **pixels, int *width, int *height) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - FILE *fin; - byte *targa_rgba; - TargaHeader targa_header; - - fin = fopen (name, "rb"); - if (!fin) - Error ("Couldn't read %s", name); - - targa_header.id_length = fgetc(fin); - targa_header.colormap_type = fgetc(fin); - targa_header.image_type = fgetc(fin); - - targa_header.colormap_index = fgetLittleShort(fin); - targa_header.colormap_length = fgetLittleShort(fin); - targa_header.colormap_size = fgetc(fin); - targa_header.x_origin = fgetLittleShort(fin); - targa_header.y_origin = fgetLittleShort(fin); - targa_header.width = fgetLittleShort(fin); - targa_header.height = fgetLittleShort(fin); - targa_header.pixel_size = fgetc(fin); - targa_header.attributes = fgetc(fin); - - if (targa_header.image_type!=2 - && targa_header.image_type!=10) - Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n"); - - if (targa_header.colormap_type !=0 - || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) - Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - targa_rgba = malloc(numPixels*4); - *pixels = targa_rgba; - - if (targa_header.id_length != 0) - fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment - - if (targa_header.image_type==2) { // Uncompressed, RGB images - for(row=rows-1; row>=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column<columns; column++) { - unsigned char red,green,blue,alphabyte; - switch (targa_header.pixel_size) { - case 24: - - blue = getc(fin); - green = getc(fin); - red = getc(fin); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = getc(fin); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - } - } - } - } - else if (targa_header.image_type==10) { // Runlength encoded RGB images - unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; - for(row=rows-1; row>=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column<columns; ) { - packetHeader=getc(fin); - packetSize = 1 + (packetHeader & 0x7f); - if (packetHeader & 0x80) { // run-length packet - switch (targa_header.pixel_size) { - case 24: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = 255; - break; - case 32: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = getc(fin); - break; - } - - for(j=0;j<packetSize;j++) { - *pixbuf++=red; - *pixbuf++=green; - *pixbuf++=blue; - *pixbuf++=alphabyte; - column++; - if (column==columns) { // run spans across rows - column=0; - if (row>0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - 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); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = getc(fin); - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - } - column++; - if (column==columns) { // pixel packet run spans across rows - column=0; - if (row>0) - 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); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 (count<bpwidth); + + if (count>bpwidth) + 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) + { + if (bmhd.compression == cm_rle1) + body_p = LBMRLEDecompress ((byte *)body_p + , pic_p , bmhd.w); + else if (bmhd.compression == cm_none) + { + memcpy (pic_p,body_p,bmhd.w); + body_p += Align(bmhd.w); + } + } + + } + else + { + // + // unpack ILBM + // + Error ("%s is an interlaced LBM, not packed", filename); + } + break; + } + + LBM_P += Align(chunklength); + } + + free (LBMbuffer); + + *picture = picbuffer; + + if (palette) + *palette = cmapbuffer; +} + + +/* +============================================================================ + + WRITE LBM + +============================================================================ +*/ + +/* +============== +WriteLBMfile +============== +*/ +void WriteLBMfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + byte *lbm, *lbmptr; + int *formlength, *bmhdlength, *cmaplength, *bodylength; + int length; + bmhd_t basebmhd; + + lbm = lbmptr = malloc (width*height+1000); + +// +// start FORM +// + *lbmptr++ = 'F'; + *lbmptr++ = 'O'; + *lbmptr++ = 'R'; + *lbmptr++ = 'M'; + + formlength = (int*)lbmptr; + lbmptr+=4; // leave space for length + + *lbmptr++ = 'P'; + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = ' '; + +// +// write BMHD +// + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = 'H'; + *lbmptr++ = 'D'; + + bmhdlength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memset (&basebmhd,0,sizeof(basebmhd)); + basebmhd.w = BigShort((short)width); + basebmhd.h = BigShort((short)height); + basebmhd.nPlanes = BigShort(8); + basebmhd.xAspect = BigShort(5); + basebmhd.yAspect = BigShort(6); + basebmhd.pageWidth = BigShort((short)width); + basebmhd.pageHeight = BigShort((short)height); + + memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); + lbmptr += sizeof(basebmhd); + + length = lbmptr-(byte *)bmhdlength-4; + *bmhdlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write CMAP +// + *lbmptr++ = 'C'; + *lbmptr++ = 'M'; + *lbmptr++ = 'A'; + *lbmptr++ = 'P'; + + cmaplength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,palette,768); + lbmptr += 768; + + length = lbmptr-(byte *)cmaplength-4; + *cmaplength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write BODY +// + *lbmptr++ = 'B'; + *lbmptr++ = 'O'; + *lbmptr++ = 'D'; + *lbmptr++ = 'Y'; + + bodylength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,data,width*height); + lbmptr += width*height; + + length = lbmptr-(byte *)bodylength-4; + *bodylength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// done +// + length = lbmptr-(byte *)formlength-4; + *formlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write output file +// + SaveFile (filename, lbm, lbmptr-lbm); + free (lbm); +} + + +/* +============================================================================ + +LOAD PCX + +============================================================================ +*/ + +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; + + +/* +============== +LoadPCX +============== +*/ +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) +{ + byte *raw; + pcx_t *pcx; + int x, y; + int len; + int dataByte, runLength; + byte *out, *pix; + + // + // load the file + // + len = LoadFile (filename, (void **)&raw); + + // + // parse the PCX file + // + pcx = (pcx_t *)raw; + raw = &pcx->data; + + 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<height ; i++) + { + for (j=0 ; j<width ; j++) + { + if ( (*data & 0xc0) != 0xc0) + *pack++ = *data++; + else + { + *pack++ = 0xc1; + *pack++ = *data++; + } + } + } + + // write the palette + *pack++ = 0x0c; // palette ID byte + for (i=0 ; i<768 ; i++) + *pack++ = *palette++; + +// write output file + length = pack - (byte *)pcx; + SaveFile (filename, pcx, length); + + free (pcx); +} + + +/* +============================================================================ + +LOAD IMAGE + +============================================================================ +*/ + +/* +============== +Load256Image + +Will load either an lbm or pcx, depending on extension. +Any of the return pointers can be NULL if you don't want them. +============== +*/ +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_strncasecmp (ext, "lbm", strlen(ext) )) + { + LoadLBM (name, pixels, palette); + if (width) + *width = bmhd.w; + if (height) + *height = bmhd.h; + } + else if (!Q_strncasecmp (ext, "pcx",strlen(ext))) + { + LoadPCX (name, pixels, palette, width, height); + } + else + Error ("%s doesn't have a known image extension", name); +} + + +/* +============== +Save256Image + +Will save either an lbm or pcx, depending on extension. +============== +*/ +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_strncasecmp (ext, "lbm",strlen(ext))) + { + WriteLBMfile (name, pixels, width, height, palette); + } + else if (!Q_strncasecmp (ext, "pcx",strlen(ext))) + { + WritePCXfile (name, pixels, width, height, palette); + } + else + Error ("%s doesn't have a known image extension", name); +} + + + + +/* +============================================================================ + +TARGA IMAGE + +============================================================================ +*/ + +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; + +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); +} + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA (char *name, byte **pixels, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + FILE *fin; + byte *targa_rgba; + TargaHeader targa_header; + + fin = fopen (name, "rb"); + if (!fin) + Error ("Couldn't read %s", name); + + targa_header.id_length = fgetc(fin); + targa_header.colormap_type = fgetc(fin); + targa_header.image_type = fgetc(fin); + + targa_header.colormap_index = fgetLittleShort(fin); + targa_header.colormap_length = fgetLittleShort(fin); + targa_header.colormap_size = fgetc(fin); + targa_header.x_origin = fgetLittleShort(fin); + targa_header.y_origin = fgetLittleShort(fin); + targa_header.width = fgetLittleShort(fin); + targa_header.height = fgetLittleShort(fin); + targa_header.pixel_size = fgetc(fin); + targa_header.attributes = fgetc(fin); + + if (targa_header.image_type!=2 + && targa_header.image_type!=10) + Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type !=0 + || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24)) + Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + targa_rgba = malloc(numPixels*4); + *pixels = targa_rgba; + + if (targa_header.id_length != 0) + fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment + + if (targa_header.image_type==2) { // Uncompressed, RGB images + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; column++) { + unsigned char red,green,blue,alphabyte; + switch (targa_header.pixel_size) { + case 24: + + blue = getc(fin); + green = getc(fin); + red = getc(fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = getc(fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + } + } + } + else if (targa_header.image_type==10) { // Runlength encoded RGB images + unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; ) { + packetHeader=getc(fin); + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = 255; + break; + case 32: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = getc(fin); + break; + } + + for(j=0;j<packetSize;j++) { + *pixbuf++=red; + *pixbuf++=green; + *pixbuf++=blue; + *pixbuf++=alphabyte; + column++; + if (column==columns) { // run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + 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); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = getc(fin); + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + } + column++; + if (column==columns) { // pixel packet run spans across rows + column=0; + if (row>0) + 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 index b2055225..b51017da 100644 --- a/tools/quake2/common/lbmlib.h +++ b/tools/quake2/common/lbmlib.h @@ -1,38 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 7c06a477..84ebb2d9 100644 --- a/tools/quake2/common/mathlib.c +++ b/tools/quake2/common/mathlib.c @@ -1,172 +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; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index f6d13483..dc350ba3 100644 --- a/tools/quake2/common/mathlib.h +++ b/tools/quake2/common/mathlib.h @@ -1,75 +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 <math.h> - -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <math.h> + +#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/path_init.c b/tools/quake2/common/path_init.c index 6e01d3fd..bf731c99 100644 --- a/tools/quake2/common/path_init.c +++ b/tools/quake2/common/path_init.c @@ -1,400 +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 <unistd.h> - #include <pwd.h> - #include <limits.h> -#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" ); -} - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <unistd.h> + #include <pwd.h> + #include <limits.h> +#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 index 47b2007e..6639d241 100644 --- a/tools/quake2/common/polylib.c +++ b/tools/quake2/common/polylib.c @@ -1,642 +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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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 index 6c21fc95..43515cf3 100644 --- a/tools/quake2/common/polylib.h +++ b/tools/quake2/common/polylib.h @@ -1,54 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e919c264..2b20c8d7 100644 --- a/tools/quake2/common/q2_threads.h +++ b/tools/quake2/common/q2_threads.h @@ -1,34 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 434accc7..1dd9d0ae 100644 --- a/tools/quake2/common/qfiles.h +++ b/tools/quake2/common/qfiles.h @@ -1,563 +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; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 986f381c..07600a08 100644 --- a/tools/quake2/common/scriplib.c +++ b/tools/quake2/common/scriplib.c @@ -1,296 +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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 05b67ce0..48a75c6a 100644 --- a/tools/quake2/common/scriplib.h +++ b/tools/quake2/common/scriplib.h @@ -1,43 +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); - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 9de00199..a2e8a810 100644 --- a/tools/quake2/common/threads.c +++ b/tools/quake2/common/threads.c @@ -1,622 +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 <pthread.h> -#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 <windows.h> - -// 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<numthreads ; i++) - { - threadhandle[i] = CreateThread( - NULL, // LPSECURITY_ATTRIBUTES lpsa, - //0, // DWORD cbStack, - - /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ - (4096 * 1024), - - (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, - (LPVOID)i, // LPVOID lpvThreadParm, - 0, // DWORD fdwCreate, - &threadid[i]); - } - - for (i=0 ; i<numthreads ; i++) - WaitForSingleObject (threadhandle[i], INFINITE); - } - DeleteCriticalSection (&crit); - - threaded = false; - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -OSF1 - -=================================================================== -*/ - -#ifdef __osf__ -#define USED - -int numthreads = 4; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - numthreads = 4; - } -} - - -#include <pthread.h> - -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<numthreads ; i++) - { - if (pthread_create(&work_threads[i], attrib - , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) - Error ("pthread_create failed"); - } - - for (i=0 ; i<numthreads ; i++) - { - if (pthread_join (work_threads[i], &status) == -1) - Error ("pthread_join failed"); - } - - threaded = false; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -IRIX - -=================================================================== -*/ - -#ifdef _MIPS_ISA -#define USED - -#include <task.h> -#include <abi_mutex.h> -#include <sys/types.h> -#include <sys/prctl.h> - - -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<numthreads-1 ; i++) - { - pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i - , NULL, 0x200000); // 2 meg stacks - if (pid[i] == -1) - { - perror ("sproc"); - Error ("sproc failed"); - } - } - - func(i); - - for (i=0 ; i<numthreads-1 ; i++) - wait (NULL); - - threaded = false; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - - -/* -======================================================================= - - Linux pthreads - -======================================================================= -*/ - -#if defined( __linux__ ) || defined( __APPLE__ ) -#define USED - -// Setting default Threads to 1 -int numthreads = 1; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - /* default to one thread, only multi-thread when specifically told to */ - numthreads = 1; - } - if(numthreads > 1) - Sys_Printf("threads: %d\n", numthreads); -} - -#include <pthread.h> - -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<numthreads ; i++) - { - /* Default pthread attributes: joinable & non-realtime scheduling */ - if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) - Error("pthread_create failed"); - } - for (i=0 ; i<numthreads ; i++) - { - if(pthread_join(work_threads[i], (void **)&status) != 0) - Error("pthread_join failed"); - } - pthread_mutexattr_destroy(&mattrib); - threaded = false; - } - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} -#endif // ifdef __linux__ - - -/* -======================================================================= - - SINGLE THREAD - -======================================================================= -*/ - -#ifndef USED - -int numthreads = 1; - -void ThreadSetDefault (void) -{ - numthreads = 1; -} - -void ThreadLock (void) -{ -} - -void ThreadUnlock (void) -{ -} - -/* -============= -RunThreadsOn -============= -*/ -void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) -{ - int i; - int start, end; - - dispatch = 0; - workcount = workcnt; - oldf = -1; - pacifier = showpacifier; - start = I_FloatTime (); - func(0); - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <pthread.h> +#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 <windows.h> + +// 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<numthreads ; i++) + { + threadhandle[i] = CreateThread( + NULL, // LPSECURITY_ATTRIBUTES lpsa, + //0, // DWORD cbStack, + + /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ + (4096 * 1024), + + (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, + (LPVOID)i, // LPVOID lpvThreadParm, + 0, // DWORD fdwCreate, + &threadid[i]); + } + + for (i=0 ; i<numthreads ; i++) + WaitForSingleObject (threadhandle[i], INFINITE); + } + DeleteCriticalSection (&crit); + + threaded = false; + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +OSF1 + +=================================================================== +*/ + +#ifdef __osf__ +#define USED + +int numthreads = 4; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + numthreads = 4; + } +} + + +#include <pthread.h> + +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<numthreads ; i++) + { + if (pthread_create(&work_threads[i], attrib + , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) + Error ("pthread_create failed"); + } + + for (i=0 ; i<numthreads ; i++) + { + if (pthread_join (work_threads[i], &status) == -1) + Error ("pthread_join failed"); + } + + threaded = false; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +IRIX + +=================================================================== +*/ + +#ifdef _MIPS_ISA +#define USED + +#include <task.h> +#include <abi_mutex.h> +#include <sys/types.h> +#include <sys/prctl.h> + + +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<numthreads-1 ; i++) + { + pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i + , NULL, 0x200000); // 2 meg stacks + if (pid[i] == -1) + { + perror ("sproc"); + Error ("sproc failed"); + } + } + + func(i); + + for (i=0 ; i<numthreads-1 ; i++) + wait (NULL); + + threaded = false; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + + +/* +======================================================================= + + Linux pthreads + +======================================================================= +*/ + +#if defined( __linux__ ) || defined( __APPLE__ ) +#define USED + +// Setting default Threads to 1 +int numthreads = 1; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + /* default to one thread, only multi-thread when specifically told to */ + numthreads = 1; + } + if(numthreads > 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include <pthread.h> + +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<numthreads ; i++) + { + /* Default pthread attributes: joinable & non-realtime scheduling */ + if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) + Error("pthread_create failed"); + } + for (i=0 ; i<numthreads ; i++) + { + if(pthread_join(work_threads[i], (void **)&status) != 0) + Error("pthread_join failed"); + } + pthread_mutexattr_destroy(&mattrib); + threaded = false; + } + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} +#endif // ifdef __linux__ + + +/* +======================================================================= + + SINGLE THREAD + +======================================================================= +*/ + +#ifndef USED + +int numthreads = 1; + +void ThreadSetDefault (void) +{ + numthreads = 1; +} + +void ThreadLock (void) +{ +} + +void ThreadUnlock (void) +{ +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int start, end; + + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + start = I_FloatTime (); + func(0); + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + +#endif diff --git a/tools/quake2/common/trilib.c b/tools/quake2/common/trilib.c index 11f718f5..05b0cf36 100644 --- a/tools/quake2/common/trilib.c +++ b/tools/quake2/common/trilib.c @@ -1,186 +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 -*/ -// -// trilib.c: library for loading triangles from an Alias triangle file -// - -#include <stdio.h> -#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 ; i<sizeof(tf_triangle)/4 ; i++) - { - ((int *)tri)[i] = BigLong (((int *)tri)[i]); - } -} - -void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles) -{ - FILE *input; - float start; - char name[256], tex[256]; - int i, count, magic; - tf_triangle tri; - triangle_t *ptri; - 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); - - ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); - - *pptri = ptri; - - 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' ); - -// 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' ); - -// 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. */ - /* Mia culpa. */ - --iLevel; - i = -1; - do { - ++i; - fread( &(name[i]), sizeof( char ), 1, input); - } while( name[i] != '\0' ); - -// indent(); -// fprintf(stdout,"OBJECT END: %s\n",name); - continue; - } - } - -// -// read the triangles -// - for (i = 0; i < count; ++i) { - int j; - - fread( &tri, sizeof(tf_triangle), 1, input ); - ByteSwapTri (&tri); - for (j=0 ; j<3 ; j++) - { - int k; - - for (k=0 ; k<3 ; k++) - { - ptri->verts[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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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 ; i<sizeof(tf_triangle)/4 ; i++) + { + ((int *)tri)[i] = BigLong (((int *)tri)[i]); + } +} + +void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles) +{ + FILE *input; + float start; + char name[256], tex[256]; + int i, count, magic; + tf_triangle tri; + triangle_t *ptri; + 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); + + ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + + 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' ); + +// 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' ); + +// 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. */ + /* Mia culpa. */ + --iLevel; + i = -1; + do { + ++i; + fread( &(name[i]), sizeof( char ), 1, input); + } while( name[i] != '\0' ); + +// indent(); +// fprintf(stdout,"OBJECT END: %s\n",name); + continue; + } + } + +// +// read the triangles +// + for (i = 0; i < count; ++i) { + int j; + + fread( &tri, sizeof(tf_triangle), 1, input ); + ByteSwapTri (&tri); + for (j=0 ; j<3 ; j++) + { + int k; + + for (k=0 ; k<3 ; k++) + { + ptri->verts[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 index 406ae1d9..4cdad831 100644 --- a/tools/quake2/common/trilib.h +++ b/tools/quake2/common/trilib.h @@ -1,31 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 64ebd48e..63f861b7 100644 --- a/tools/quake2/q2map/brushbsp.c +++ b/tools/quake2/q2map/brushbsp.c @@ -1,1329 +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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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;i<brush->numsides ; 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 ; i<brush->numsides ; i++) - { - w = brush->sides[i].winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) - { - side = &brush->sides[i]; - plane = &mapplanes[side->planenum]; - w = BaseWindingForPlane (plane->normal, plane->dist); - for (j=0 ; j<brush->numsides && 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 ; i<brush->numsides ; 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 ( ; i<brush->numsides ; 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 ; i<brushes->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; j<w->numpoints; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<b->numsides ; 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 ; i<brush->numsides ; 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 ; j<test->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; i++) - { - w = brush->sides[i].winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) - { - w = brush->sides[i].winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides && 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 ; i<brush->numsides ; 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 ; i<newbrush->numsides ; 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 ; i<b->numsides ; 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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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;i<brush->numsides ; 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 ; i<brush->numsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) + { + side = &brush->sides[i]; + plane = &mapplanes[side->planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; j<brush->numsides && 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 ; i<brush->numsides ; 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 ( ; i<brush->numsides ; 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 ; i<brushes->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; 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 ; j<w->numpoints; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<b->numsides ; 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 ; i<brush->numsides ; 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 ; j<test->numsides ; 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 ; i<brush->numsides ; 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 ; i<brush->numsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides && 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 ; i<brush->numsides ; 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 ; i<newbrush->numsides ; 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 ; i<b->numsides ; 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 index 6e750be7..dc2bdab4 100644 --- a/tools/quake2/q2map/csg.c +++ b/tools/quake2/q2map/csg.c @@ -1,634 +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 ; i<b->numsides && 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 ; i<b->numsides && 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 ; i<a->numsides ; i++) - { - for (j=0 ; j<b->numsides ; 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 ; i<brush->numsides ; 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 ; i<endbrush ; i++) - { - mb = &mapbrushes[i]; - - numsides = mb->numsides; - if (!numsides) - continue; - // make sure the brush has at least one face showing - vis = 0; - for (j=0 ; j<numsides ; j++) - if (mb->original_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 ; j<numsides ; j++) - { - if (newbrush->sides[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 ; i<list->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; 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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<b->numsides && 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 ; i<b->numsides && 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 ; i<a->numsides ; i++) + { + for (j=0 ; j<b->numsides ; 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 ; i<brush->numsides ; 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 ; i<endbrush ; i++) + { + mb = &mapbrushes[i]; + + numsides = mb->numsides; + if (!numsides) + continue; + // make sure the brush has at least one face showing + vis = 0; + for (j=0 ; j<numsides ; j++) + if (mb->original_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 ; j<numsides ; j++) + { + if (newbrush->sides[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 ; i<list->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; 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 index 0b7ba80f..4839f9c0 100644 --- a/tools/quake2/q2map/faces.c +++ b/tools/quake2/q2map/faces.c @@ -1,1076 +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])<POINT_EPSILON - && fabs(p[1]-vert[1])<POINT_EPSILON - && fabs(p[2]-vert[2])<POINT_EPSILON ) - return vnum; - } - -// emit a vertex - if (numvertexes == MAX_MAP_VERTS) - Error ("numvertexes == MAX_MAP_VERTS"); - - dvertexes[numvertexes].point[0] = vert[0]; - dvertexes[numvertexes].point[1] = vert[1]; - dvertexes[numvertexes].point[2] = vert[2]; - - vertexchain[numvertexes] = hashverts[h]; - hashverts[h] = numvertexes; - - c_uniqueverts++; - - numvertexes++; - - return numvertexes-1; -} -#else -/* -================== -GetVertexnum - -Dumb linear search -================== -*/ -int GetVertexnum (vec3_t v) -{ - int i, j; - dvertex_t *dv; - vec_t d; - - c_totalverts++; - - // make really close values exactly integral - for (i=0 ; i<3 ; i++) - { - if ( fabs(v[i] - (int)(v[i]+0.5)) < INTEGRAL_EPSILON ) - v[i] = (int)(v[i]+0.5); - if (v[i] < -4096 || v[i] > 4096) - Error ("GetVertexnum: outside +/- 4096"); - } - - // search for an existing vertex match - for (i=0, dv=dvertexes ; i<numvertexes ; i++, dv++) - { - for (j=0 ; j<3 ; j++) - { - d = v[j] - dv->point[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 ; i<MAXEDGES ; i++) - newf->vertexnums[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 ; i<remaining ; i++) - f->vertexnums[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 ; i<w->numpoints ; 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<numvertexes-1 ; i++) - edge_verts[i] = i+1; -} -#endif - - x1 = (4096 + (int)(v1[0]+0.5)) >> 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<num_edge_verts ; i++) - edge_verts[i] = i+1; -} -#endif - -/* -========== -TestEdge - -Can be recursively reentered -========== -*/ -void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert) -{ - int j, k; - vec_t dist; - vec3_t delta; - vec3_t exact; - vec3_t off; - vec_t error; - vec3_t p; - - if (p1 == p2) - { - c_degenerate++; - return; // degenerate edge - } - - for (k=startvert ; k<num_edge_verts ; k++) - { - j = edge_verts[k]; - if (j==p1 || j == p2) - continue; - - VectorCopy (dvertexes[j].point, p); - - VectorSubtract (p, edge_start, delta); - dist = DotProduct (delta, edge_dir); - if (dist <=start || dist >= 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 ; i<f->numpoints ; 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 ; i<f->numpoints ; 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 ; i<f1->numpoints ; i++) - { - p1 = f1->p[i]; - p2 = f1->p[(i+1)%f1->numpoints]; - for (j=0 ; j<f2->numpoints ; 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 ; i<w->numpoints ; 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); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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])<POINT_EPSILON + && fabs(p[1]-vert[1])<POINT_EPSILON + && fabs(p[2]-vert[2])<POINT_EPSILON ) + return vnum; + } + +// emit a vertex + if (numvertexes == MAX_MAP_VERTS) + Error ("numvertexes == MAX_MAP_VERTS"); + + dvertexes[numvertexes].point[0] = vert[0]; + dvertexes[numvertexes].point[1] = vert[1]; + dvertexes[numvertexes].point[2] = vert[2]; + + vertexchain[numvertexes] = hashverts[h]; + hashverts[h] = numvertexes; + + c_uniqueverts++; + + numvertexes++; + + return numvertexes-1; +} +#else +/* +================== +GetVertexnum + +Dumb linear search +================== +*/ +int GetVertexnum (vec3_t v) +{ + int i, j; + dvertex_t *dv; + vec_t d; + + c_totalverts++; + + // make really close values exactly integral + for (i=0 ; i<3 ; i++) + { + if ( fabs(v[i] - (int)(v[i]+0.5)) < INTEGRAL_EPSILON ) + v[i] = (int)(v[i]+0.5); + if (v[i] < -4096 || v[i] > 4096) + Error ("GetVertexnum: outside +/- 4096"); + } + + // search for an existing vertex match + for (i=0, dv=dvertexes ; i<numvertexes ; i++, dv++) + { + for (j=0 ; j<3 ; j++) + { + d = v[j] - dv->point[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 ; i<MAXEDGES ; i++) + newf->vertexnums[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 ; i<remaining ; i++) + f->vertexnums[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 ; i<w->numpoints ; 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<numvertexes-1 ; i++) + edge_verts[i] = i+1; +} +#endif + + x1 = (4096 + (int)(v1[0]+0.5)) >> 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<num_edge_verts ; i++) + edge_verts[i] = i+1; +} +#endif + +/* +========== +TestEdge + +Can be recursively reentered +========== +*/ +void TestEdge (vec_t start, vec_t end, int p1, int p2, int startvert) +{ + int j, k; + vec_t dist; + vec3_t delta; + vec3_t exact; + vec3_t off; + vec_t error; + vec3_t p; + + if (p1 == p2) + { + c_degenerate++; + return; // degenerate edge + } + + for (k=startvert ; k<num_edge_verts ; k++) + { + j = edge_verts[k]; + if (j==p1 || j == p2) + continue; + + VectorCopy (dvertexes[j].point, p); + + VectorSubtract (p, edge_start, delta); + dist = DotProduct (delta, edge_dir); + if (dist <=start || dist >= 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 ; i<f->numpoints ; 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 ; i<f->numpoints ; 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 ; i<f1->numpoints ; i++) + { + p1 = f1->p[i]; + p2 = f1->p[(i+1)%f1->numpoints]; + for (j=0 ; j<f2->numpoints ; 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 ; i<w->numpoints ; 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 index 9a34f6f9..d831fbf0 100644 --- a/tools/quake2/q2map/flow.c +++ b/tools/quake2/q2map/flow.c @@ -1,787 +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<numbits ; i++) - if (bits[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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<source->numpoints ; 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 ; j<pass->numpoints ; 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 ; k<source->numpoints ; 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 ; k<pass->numpoints ; 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 ; i<leaf->numportals ; 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 ; j<portallongs ; j++) - { - might[j] = ((long *)prevstack->mightsee)[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 ; i<portallongs ; i++) - ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[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 ; i<leaf->numportals ; 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 ; j<numportals*2 ; j++, tp++) - { - if (j == portalnum) - continue; - w = tp->winding; - for (k=0 ; k<w->numpoints ; 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 ; k<w->numpoints ; 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 ; i<leaf->numportals ; 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 ; j<portallongs ; j++) - { - ((long *)newmight)[j] = ((long *)mightsee)[j] - & ((long *)p->portalflood)[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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<numbits ; i++) + if (bits[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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<source->numpoints ; 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 ; j<pass->numpoints ; 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 ; k<source->numpoints ; 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 ; k<pass->numpoints ; 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 ; i<leaf->numportals ; 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 ; j<portallongs ; j++) + { + might[j] = ((long *)prevstack->mightsee)[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 ; i<portallongs ; i++) + ((long *)data.pstack_head.mightsee)[i] = ((long *)p->portalflood)[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 ; i<leaf->numportals ; 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 ; j<numportals*2 ; j++, tp++) + { + if (j == portalnum) + continue; + w = tp->winding; + for (k=0 ; k<w->numpoints ; 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 ; k<w->numpoints ; 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 ; i<leaf->numportals ; 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 ; j<portallongs ; j++) + { + ((long *)newmight)[j] = ((long *)mightsee)[j] + & ((long *)p->portalflood)[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 index d3f78f53..d36355f8 100644 --- a/tools/quake2/q2map/gldraw.c +++ b/tools/quake2/q2map/gldraw.c @@ -1,231 +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 <windows.h> -#include <GL/gl.h> -#include <GL/glu.h> -#include <GL/glaux.h> - -#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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#include <GL/gl.h> +#include <GL/glu.h> +#include <GL/glaux.h> + +#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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 index a5c0e30b..b08053bd 100644 --- a/tools/quake2/q2map/glfile.c +++ b/tools/quake2/q2map/glfile.c @@ -1,148 +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 ; i<w->numpoints ; 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 index 32d57b9c..6c814b20 100644 --- a/tools/quake2/q2map/leakfile.c +++ b/tools/quake2/q2map/leakfile.c @@ -1,180 +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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 62a61ebd..cc5da84d 100644 --- a/tools/quake2/q2map/lightmap.c +++ b/tools/quake2/q2map/lightmap.c @@ -1,1315 +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 ; i<numfaces ; i++, f++) - { - facelinks[i] = planelinks[f->side][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 ; i<numfaces ; i++, f++) - { - for (j=0 ; j<f->numedges ; 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 ; i<trian->numpoints ; i++) - { - p1 = trian->points[i]->origin; - for (j=i+1 ; j<trian->numpoints ; 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)<ON_EPSILON || fabs(x2)<ON_EPSILON) - { - VectorCopy (base, color); - return; - } - - VectorMA (base, x/x2, d2, color); - VectorMA (color, y/y1, d1, color); -} - -qboolean PointInTriangle (vec3_t point, triangle_t *t) -{ - int i; - triedge_t *e; - vec_t d; - - for (i=0 ; i<3 ; i++) - { - e = t->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 ; j<trian->numpoints ; 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 ; i<s->numedges ; 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 ; t<h ; t++) - { - for (s=0 ; s<w ; s++, surf+=3) - { - us = starts + (s+sofs)*step; - ut = startt + (t+tofs)*step; - - - // if a line can be traced from surf to facemid, the point is good - for (i=0 ; i<6 ; i++) - { - // calculate texture point - for (j=0 ; j<3 ; j++) - surf[j] = l->texorg[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 ; i<num_entities ; i++) - { - n = ValueForKey (&entities[i], "targetname"); - if (!strcmp (n, target)) - return &entities[i]; - } - - return NULL; -} - -//#define DIRECT_LIGHT 3000 -#define DIRECT_LIGHT 3 - -/* -============= -CreateDirectLights -============= -*/ -void CreateDirectLights (void) -{ - int i; - patch_t *p; - directlight_t *dl; - dleaf_t *leaf; - int cluster; - entity_t *e, *e2; - char *name; - char *target; - float angle; - vec3_t dest; - char *_color; - float intensity; - - // - // surfaces - // - for (i=0, p=patches ; i< (int) num_patches ; i++, p++) - { - if (p->totallight[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 ; i<num_entities ; i++) - { - e = &entities[i]; - name = ValueForKey (e, "classname"); - if (strncmp (name, "light", 5)) - continue; - - numdlights++; - dl = malloc(sizeof(directlight_t)); - memset (dl, 0, sizeof(*dl)); - - GetVectorForKey (e, "origin", dl->origin); - 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 ; i<dvis->numclusters ; 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 ; i<numsamples ; i++) - { - memset (&l[i], 0, sizeof(l[i])); - l[i].surfnum = facenum; - l[i].face = f; - VectorCopy (dplanes[f->planenum].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 ; i<l[0].numsurfpt ; i++) - { - for (j=0 ; j<numsamples ; j++) - { - GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable, - i*3, tablesize, 1.0/numsamples); - } - - // contribute the sample to one or more patches - AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum); - } - - // average up the direct light on each patch for radiosity - for (patch = face_patches[facenum] ; patch ; patch=patch->next) - { - if (patch->samples) - { - VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight); - } - else - { -// printf ("patch with no samples\n"); - } - } - - for (i=0 ; i<MAX_LSTYLES ; i++) - { - if (!styletable[i]) - continue; - if (fl->numstyles == 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 ; i<l[0].numsurfpt ; i++, spot+=3) - { - VectorAdd (spot, face_patches[facenum]->baselight, 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 ; i<f->numedges ; 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 ; i<trian->numpoints ; 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 ; st<fl->numstyles ; st++) - { - f->styles[st] = fl->stylenums[st]; - for (j=0 ; j<fl->numsamples ; 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); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<numfaces ; i++, f++) + { + facelinks[i] = planelinks[f->side][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 ; i<numfaces ; i++, f++) + { + for (j=0 ; j<f->numedges ; 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 ; i<trian->numpoints ; i++) + { + p1 = trian->points[i]->origin; + for (j=i+1 ; j<trian->numpoints ; 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)<ON_EPSILON || fabs(x2)<ON_EPSILON) + { + VectorCopy (base, color); + return; + } + + VectorMA (base, x/x2, d2, color); + VectorMA (color, y/y1, d1, color); +} + +qboolean PointInTriangle (vec3_t point, triangle_t *t) +{ + int i; + triedge_t *e; + vec_t d; + + for (i=0 ; i<3 ; i++) + { + e = t->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 ; j<trian->numpoints ; 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 ; i<s->numedges ; 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 ; t<h ; t++) + { + for (s=0 ; s<w ; s++, surf+=3) + { + us = starts + (s+sofs)*step; + ut = startt + (t+tofs)*step; + + + // if a line can be traced from surf to facemid, the point is good + for (i=0 ; i<6 ; i++) + { + // calculate texture point + for (j=0 ; j<3 ; j++) + surf[j] = l->texorg[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 ; i<num_entities ; i++) + { + n = ValueForKey (&entities[i], "targetname"); + if (!strcmp (n, target)) + return &entities[i]; + } + + return NULL; +} + +//#define DIRECT_LIGHT 3000 +#define DIRECT_LIGHT 3 + +/* +============= +CreateDirectLights +============= +*/ +void CreateDirectLights (void) +{ + int i; + patch_t *p; + directlight_t *dl; + dleaf_t *leaf; + int cluster; + entity_t *e, *e2; + char *name; + char *target; + float angle; + vec3_t dest; + char *_color; + float intensity; + + // + // surfaces + // + for (i=0, p=patches ; i< (int) num_patches ; i++, p++) + { + if (p->totallight[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 ; i<num_entities ; i++) + { + e = &entities[i]; + name = ValueForKey (e, "classname"); + if (strncmp (name, "light", 5)) + continue; + + numdlights++; + dl = malloc(sizeof(directlight_t)); + memset (dl, 0, sizeof(*dl)); + + GetVectorForKey (e, "origin", dl->origin); + 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 ; i<dvis->numclusters ; 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 ; i<numsamples ; i++) + { + memset (&l[i], 0, sizeof(l[i])); + l[i].surfnum = facenum; + l[i].face = f; + VectorCopy (dplanes[f->planenum].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 ; i<l[0].numsurfpt ; i++) + { + for (j=0 ; j<numsamples ; j++) + { + GatherSampleLight (l[j].surfpt[i], l[0].facenormal, styletable, + i*3, tablesize, 1.0/numsamples); + } + + // contribute the sample to one or more patches + AddSampleToPatch (l[0].surfpt[i], styletable[0]+i*3, facenum); + } + + // average up the direct light on each patch for radiosity + for (patch = face_patches[facenum] ; patch ; patch=patch->next) + { + if (patch->samples) + { + VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight); + } + else + { +// printf ("patch with no samples\n"); + } + } + + for (i=0 ; i<MAX_LSTYLES ; i++) + { + if (!styletable[i]) + continue; + if (fl->numstyles == 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 ; i<l[0].numsurfpt ; i++, spot+=3) + { + VectorAdd (spot, face_patches[facenum]->baselight, 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 ; i<f->numedges ; 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 ; i<trian->numpoints ; 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 ; st<fl->numstyles ; st++) + { + f->styles[st] = fl->stylenums[st]; + for (j=0 ; j<fl->numsamples ; 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 index 6edcc21c..810205a5 100644 --- a/tools/quake2/q2map/main.c +++ b/tools/quake2/q2map/main.c @@ -1,721 +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 <value> [-v] <mapname>\n" ); - return 0; - } - - // get scale - scale = atof( argv[ argc - 2 ] ); - if( scale == 0.0f ) - { - Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\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 <value> [-v] <mapname>\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<argc ; i++) - { - if (!strcmp(argv[i],"-glview")) - { - glview = true; - } - else if (!strcmp(argv[i], "-draw")) - { - Sys_Printf ("drawflag = true\n"); - drawflag = true; - } - else if (!strcmp(argv[i], "-noweld")) - { - Sys_Printf ("noweld = true\n"); - noweld = true; - } - else if (!strcmp(argv[i], "-nocsg")) - { - Sys_Printf ("nocsg = true\n"); - nocsg = true; - } - else if (!strcmp(argv[i], "-noshare")) - { - Sys_Printf ("noshare = true\n"); - noshare = true; - } - else if (!strcmp(argv[i], "-notjunc")) - { - Sys_Printf ("notjunc = true\n"); - notjunc = true; - } - else if (!strcmp(argv[i], "-nowater")) - { - Sys_Printf ("nowater = true\n"); - nowater = true; - } - else if (!strcmp(argv[i], "-noopt")) - { - Sys_Printf ("noopt = true\n"); - noopt = true; - } - else if (!strcmp(argv[i], "-noprune")) - { - Sys_Printf ("noprune = true\n"); - noprune = true; - } - else if (!strcmp(argv[i], "-nofill")) - { - Sys_Printf ("nofill = true\n"); - nofill = true; - } - else if (!strcmp(argv[i], "-nomerge")) - { - Sys_Printf ("nomerge = true\n"); - nomerge = true; - } - else if (!strcmp(argv[i], "-nosubdiv")) - { - Sys_Printf ("nosubdiv = true\n"); - nosubdiv = true; - } - else if (!strcmp(argv[i], "-nodetail")) - { - Sys_Printf ("nodetail = true\n"); - nodetail = true; - } - else if (!strcmp(argv[i], "-fulldetail")) - { - Sys_Printf ("fulldetail = true\n"); - fulldetail = true; - } - else if (!strcmp(argv[i], "-onlyents")) - { - Sys_Printf ("onlyents = true\n"); - onlyents = true; - } - else if (!strcmp(argv[i], "-micro")) - { - microvolume = atof(argv[i+1]); - Sys_Printf ("microvolume = %f\n", microvolume); - i++; - } - else if (!strcmp(argv[i], "-leaktest")) - { - Sys_Printf ("leaktest = true\n"); - leaktest = true; - } - else if (!strcmp(argv[i], "-verboseentities")) - { - Sys_Printf ("verboseentities = true\n"); - verboseentities = true; - } - else if (!strcmp(argv[i], "-chop")) - { - subdivide_size = atof(argv[i+1]); - Sys_Printf ("subdivide_size = %f\n", subdivide_size); - i++; - } - else if (!strcmp(argv[i], "-block")) - { - block_xl = block_xh = atoi(argv[i+1]); - block_yl = block_yh = atoi(argv[i+2]); - Sys_Printf ("block: %i,%i\n", block_xl, block_yl); - i+=2; - } - else if (!strcmp(argv[i], "-blocks")) - { - block_xl = atoi(argv[i+1]); - block_yl = atoi(argv[i+2]); - block_xh = atoi(argv[i+3]); - block_yh = atoi(argv[i+4]); - Sys_Printf ("blocks: %i,%i to %i,%i\n", - block_xl, block_yl, block_xh, block_yh); - i+=4; - } - else if (!strcmp (argv[i],"-tmpout")) - { - strcpy (outbase, "/tmp"); - } - else - break; - } - - - return 0; -} - -int Check_VIS_Options( int argc, char **argv ) -{ - int i; - - for (i=1 ; i<argc ; i++) - { - if (!strcmp(argv[i], "-fast")) - { - Sys_Printf ("fastvis = true\n"); - fastvis = true; - } - else if (!strcmp(argv[i], "-level")) - { - testlevel = atoi(argv[i+1]); - Sys_Printf ("testlevel = %i\n", testlevel); - i++; - } - else if (!strcmp (argv[i],"-nosort")) - { - Sys_Printf ("nosort = true\n"); - nosort = true; - } - else if (!strcmp (argv[i],"-tmpin")) - strcpy (inbase, "/tmp"); - else if (!strcmp (argv[i],"-tmpout")) - strcpy (outbase, "/tmp"); - else - break; - } - - return 0; -} - -int Check_RAD_Options( int argc, char **argv ) -{ - int i; - - for (i=1 ; i<argc ; i++) - { - if (!strcmp(argv[i],"-dump")) - dumppatches = true; - else if (!strcmp(argv[i],"-bounce")) - { - numbounce = atoi (argv[i+1]); - i++; - } - else if (!strcmp(argv[i],"-extra")) - { - extrasamples = true; - Sys_Printf ("extrasamples = true\n"); - } - else if (!strcmp(argv[i],"-chop")) - { - subdiv = atoi (argv[i+1]); - i++; - } - else if (!strcmp(argv[i],"-scale")) - { - lightscale = atof (argv[i+1]); - i++; - } - else if (!strcmp(argv[i],"-direct")) - { - direct_scale *= atof(argv[i+1]); - Sys_Printf ("direct light scaling at %f\n", direct_scale); - i++; - } - else if (!strcmp(argv[i],"-entity")) - { - entity_scale *= atof(argv[i+1]); - Sys_Printf ("entity light scaling at %f\n", entity_scale); - i++; - } - else if (!strcmp(argv[i],"-glview")) - { - glview = true; - Sys_Printf ("glview = true\n"); - } - else if (!strcmp(argv[i],"-nopvs")) - { - nopvs = true; - Sys_Printf ("nopvs = true\n"); - } - else if (!strcmp(argv[i],"-ambient")) - { - ambient = atof (argv[i+1]) * 128; - i++; - } - else if (!strcmp(argv[i],"-maxlight")) - { - maxlight = atof (argv[i+1]) * 128; - i++; - } - else if (!strcmp (argv[i],"-tmpin")) - strcpy (inbase, "/tmp"); - else if (!strcmp (argv[i],"-tmpout")) - strcpy (outbase, "/tmp"); - else - break; - } - - return 0; -} - -/* -main() -*/ - -int main( int argc, char **argv ) -{ - int i; - int r=0; - int total_time; - double start, end; - int alt_argc; - char** alt_argv; - qboolean do_info=qfalse; - qboolean do_bsp=qfalse; - qboolean do_vis=qfalse; - qboolean do_rad=qfalse; - - - /* we want consistent 'randomness' */ - srand( 0 ); - - /* start timer */ - start = I_FloatTime(); - - Sys_Printf( "\nQ2Map - Ver. 1.0\n" ); - - /* set exit call */ - //atexit( ExitQ3Map ); - - game[0] = 0; - - if ( argc < 2 ) - { - Sys_Printf(" %s: -game [quake2,heretic2] -fs_basepath basepath -info -bsp -vis -rad mapname\n",argv[0]); - return -1; - } - /* read general options first */ - for( i = 1; i < argc; i++ ) - { - /* -connect */ - if( !strcmp( argv[ i ], "-connect" ) ) - { - i++; - Broadcast_Setup( argv[ i ] ); - } - - /* verbose */ - else if( !strcmp( argv[ i ], "-v" ) ) - { - verbose = qtrue; - } - - /* threads */ - else if( !strcmp( argv[ i ], "-threads" ) ) - { - i++; - numthreads = atoi( argv[ i ] ); - } - else if( !strcmp( argv[ i ], "-game" ) ) - { - i++; - strncpy (game, argv[ i ] , 64); - strlower(game); - } - } - - /* set number of threads */ - ThreadSetDefault(); - - /* ydnar: new path initialization */ - InitPaths( &argc, argv ); - - /* read compiling options */ - for( i = 1; i < argc; i++ ) - { - /* info */ - if( !strcmp( argv[ i ], "-info" ) ) - { - do_info=qtrue; - } - - /* bsp */ - if( !strcmp( argv[ i ], "-bsp" ) ) - { - do_bsp=qtrue; - alt_argc=argc - i; - alt_argv= (char **) ( argv + i ); - Check_BSP_Options( alt_argc, alt_argv ); - } - - /* vis */ - if( !strcmp( argv[ i ], "-vis" ) ) - { - do_vis=qtrue; - alt_argc=argc - i; - alt_argv= (char **) ( argv + i ); - Check_VIS_Options( alt_argc, alt_argv ); - } - - /* rad */ - if( !strcmp( argv[ i ], "-rad" ) ) - { - do_rad=qtrue; - alt_argc=argc - i; - alt_argv= (char **) ( argv + i ); - Check_RAD_Options( alt_argc, alt_argv ); - } - } - - if (game[0] == 0) - strncpy( game, "quake2", 7); - - Sys_Printf("Game: %s\n", game); - - if ( !do_info && !do_bsp && !do_vis && !do_rad) - Sys_Printf("ERROR: -bsp, -vis, -light, nor -info specified.\nWhat to you want me to do?\n\n"); - else - { - mapname=argv[argc-1]; - - if (do_bsp) - BSP_Main(); - if (do_vis) - VIS_Main(); - if (do_rad) - RAD_Main(); - if (do_info) - BSPInfo(); - - } - - /* emit time */ - end = I_FloatTime(); - total_time = (int) (end-start); - Sys_Printf("\nTotal Time: "); - if ( total_time > 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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <value> [-v] <mapname>\n" ); + return 0; + } + + // get scale + scale = atof( argv[ argc - 2 ] ); + if( scale == 0.0f ) + { + Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\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 <value> [-v] <mapname>\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<argc ; i++) + { + if (!strcmp(argv[i],"-glview")) + { + glview = true; + } + else if (!strcmp(argv[i], "-draw")) + { + Sys_Printf ("drawflag = true\n"); + drawflag = true; + } + else if (!strcmp(argv[i], "-noweld")) + { + Sys_Printf ("noweld = true\n"); + noweld = true; + } + else if (!strcmp(argv[i], "-nocsg")) + { + Sys_Printf ("nocsg = true\n"); + nocsg = true; + } + else if (!strcmp(argv[i], "-noshare")) + { + Sys_Printf ("noshare = true\n"); + noshare = true; + } + else if (!strcmp(argv[i], "-notjunc")) + { + Sys_Printf ("notjunc = true\n"); + notjunc = true; + } + else if (!strcmp(argv[i], "-nowater")) + { + Sys_Printf ("nowater = true\n"); + nowater = true; + } + else if (!strcmp(argv[i], "-noopt")) + { + Sys_Printf ("noopt = true\n"); + noopt = true; + } + else if (!strcmp(argv[i], "-noprune")) + { + Sys_Printf ("noprune = true\n"); + noprune = true; + } + else if (!strcmp(argv[i], "-nofill")) + { + Sys_Printf ("nofill = true\n"); + nofill = true; + } + else if (!strcmp(argv[i], "-nomerge")) + { + Sys_Printf ("nomerge = true\n"); + nomerge = true; + } + else if (!strcmp(argv[i], "-nosubdiv")) + { + Sys_Printf ("nosubdiv = true\n"); + nosubdiv = true; + } + else if (!strcmp(argv[i], "-nodetail")) + { + Sys_Printf ("nodetail = true\n"); + nodetail = true; + } + else if (!strcmp(argv[i], "-fulldetail")) + { + Sys_Printf ("fulldetail = true\n"); + fulldetail = true; + } + else if (!strcmp(argv[i], "-onlyents")) + { + Sys_Printf ("onlyents = true\n"); + onlyents = true; + } + else if (!strcmp(argv[i], "-micro")) + { + microvolume = atof(argv[i+1]); + Sys_Printf ("microvolume = %f\n", microvolume); + i++; + } + else if (!strcmp(argv[i], "-leaktest")) + { + Sys_Printf ("leaktest = true\n"); + leaktest = true; + } + else if (!strcmp(argv[i], "-verboseentities")) + { + Sys_Printf ("verboseentities = true\n"); + verboseentities = true; + } + else if (!strcmp(argv[i], "-chop")) + { + subdivide_size = atof(argv[i+1]); + Sys_Printf ("subdivide_size = %f\n", subdivide_size); + i++; + } + else if (!strcmp(argv[i], "-block")) + { + block_xl = block_xh = atoi(argv[i+1]); + block_yl = block_yh = atoi(argv[i+2]); + Sys_Printf ("block: %i,%i\n", block_xl, block_yl); + i+=2; + } + else if (!strcmp(argv[i], "-blocks")) + { + block_xl = atoi(argv[i+1]); + block_yl = atoi(argv[i+2]); + block_xh = atoi(argv[i+3]); + block_yh = atoi(argv[i+4]); + Sys_Printf ("blocks: %i,%i to %i,%i\n", + block_xl, block_yl, block_xh, block_yh); + i+=4; + } + else if (!strcmp (argv[i],"-tmpout")) + { + strcpy (outbase, "/tmp"); + } + else + break; + } + + + return 0; +} + +int Check_VIS_Options( int argc, char **argv ) +{ + int i; + + for (i=1 ; i<argc ; i++) + { + if (!strcmp(argv[i], "-fast")) + { + Sys_Printf ("fastvis = true\n"); + fastvis = true; + } + else if (!strcmp(argv[i], "-level")) + { + testlevel = atoi(argv[i+1]); + Sys_Printf ("testlevel = %i\n", testlevel); + i++; + } + else if (!strcmp (argv[i],"-nosort")) + { + Sys_Printf ("nosort = true\n"); + nosort = true; + } + else if (!strcmp (argv[i],"-tmpin")) + strcpy (inbase, "/tmp"); + else if (!strcmp (argv[i],"-tmpout")) + strcpy (outbase, "/tmp"); + else + break; + } + + return 0; +} + +int Check_RAD_Options( int argc, char **argv ) +{ + int i; + + for (i=1 ; i<argc ; i++) + { + if (!strcmp(argv[i],"-dump")) + dumppatches = true; + else if (!strcmp(argv[i],"-bounce")) + { + numbounce = atoi (argv[i+1]); + i++; + } + else if (!strcmp(argv[i],"-extra")) + { + extrasamples = true; + Sys_Printf ("extrasamples = true\n"); + } + else if (!strcmp(argv[i],"-chop")) + { + subdiv = atoi (argv[i+1]); + i++; + } + else if (!strcmp(argv[i],"-scale")) + { + lightscale = atof (argv[i+1]); + i++; + } + else if (!strcmp(argv[i],"-direct")) + { + direct_scale *= atof(argv[i+1]); + Sys_Printf ("direct light scaling at %f\n", direct_scale); + i++; + } + else if (!strcmp(argv[i],"-entity")) + { + entity_scale *= atof(argv[i+1]); + Sys_Printf ("entity light scaling at %f\n", entity_scale); + i++; + } + else if (!strcmp(argv[i],"-glview")) + { + glview = true; + Sys_Printf ("glview = true\n"); + } + else if (!strcmp(argv[i],"-nopvs")) + { + nopvs = true; + Sys_Printf ("nopvs = true\n"); + } + else if (!strcmp(argv[i],"-ambient")) + { + ambient = atof (argv[i+1]) * 128; + i++; + } + else if (!strcmp(argv[i],"-maxlight")) + { + maxlight = atof (argv[i+1]) * 128; + i++; + } + else if (!strcmp (argv[i],"-tmpin")) + strcpy (inbase, "/tmp"); + else if (!strcmp (argv[i],"-tmpout")) + strcpy (outbase, "/tmp"); + else + break; + } + + return 0; +} + +/* +main() +*/ + +int main( int argc, char **argv ) +{ + int i; + int r=0; + int total_time; + double start, end; + int alt_argc; + char** alt_argv; + qboolean do_info=qfalse; + qboolean do_bsp=qfalse; + qboolean do_vis=qfalse; + qboolean do_rad=qfalse; + + + /* we want consistent 'randomness' */ + srand( 0 ); + + /* start timer */ + start = I_FloatTime(); + + Sys_Printf( "\nQ2Map - Ver. 1.0\n" ); + + /* set exit call */ + //atexit( ExitQ3Map ); + + game[0] = 0; + + if ( argc < 2 ) + { + Sys_Printf(" %s: -game [quake2,heretic2] -fs_basepath basepath -info -bsp -vis -rad mapname\n",argv[0]); + return -1; + } + /* read general options first */ + for( i = 1; i < argc; i++ ) + { + /* -connect */ + if( !strcmp( argv[ i ], "-connect" ) ) + { + i++; + Broadcast_Setup( argv[ i ] ); + } + + /* verbose */ + else if( !strcmp( argv[ i ], "-v" ) ) + { + verbose = qtrue; + } + + /* threads */ + else if( !strcmp( argv[ i ], "-threads" ) ) + { + i++; + numthreads = atoi( argv[ i ] ); + } + else if( !strcmp( argv[ i ], "-game" ) ) + { + i++; + strncpy (game, argv[ i ] , 64); + strlower(game); + } + } + + /* set number of threads */ + ThreadSetDefault(); + + /* ydnar: new path initialization */ + InitPaths( &argc, argv ); + + /* read compiling options */ + for( i = 1; i < argc; i++ ) + { + /* info */ + if( !strcmp( argv[ i ], "-info" ) ) + { + do_info=qtrue; + } + + /* bsp */ + if( !strcmp( argv[ i ], "-bsp" ) ) + { + do_bsp=qtrue; + alt_argc=argc - i; + alt_argv= (char **) ( argv + i ); + Check_BSP_Options( alt_argc, alt_argv ); + } + + /* vis */ + if( !strcmp( argv[ i ], "-vis" ) ) + { + do_vis=qtrue; + alt_argc=argc - i; + alt_argv= (char **) ( argv + i ); + Check_VIS_Options( alt_argc, alt_argv ); + } + + /* rad */ + if( !strcmp( argv[ i ], "-rad" ) ) + { + do_rad=qtrue; + alt_argc=argc - i; + alt_argv= (char **) ( argv + i ); + Check_RAD_Options( alt_argc, alt_argv ); + } + } + + if (game[0] == 0) + strncpy( game, "quake2", 7); + + Sys_Printf("Game: %s\n", game); + + if ( !do_info && !do_bsp && !do_vis && !do_rad) + Sys_Printf("ERROR: -bsp, -vis, -light, nor -info specified.\nWhat to you want me to do?\n\n"); + else + { + mapname=argv[argc-1]; + + if (do_bsp) + BSP_Main(); + if (do_vis) + VIS_Main(); + if (do_rad) + RAD_Main(); + if (do_info) + BSPInfo(); + + } + + /* emit time */ + end = I_FloatTime(); + total_time = (int) (end-start); + Sys_Printf("\nTotal Time: "); + if ( total_time > 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 index ac3be9d8..05e9df36 100644 --- a/tools/quake2/q2map/map.c +++ b/tools/quake2/q2map/map.c @@ -1,1017 +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 ; i<nummapplanes ; i++, p++) - { - if (PlaneEqual (p, normal, dist)) - return i; - } - - return CreateNewFloatPlane (normal, dist); -} -#else -int FindFloatPlane (vec3_t normal, vec_t dist) -{ - int i; - plane_t *p; - int hash, h; - - SnapPlane (normal, &dist); - hash = (int)fabs(dist) / 8; - hash &= (PLANE_HASHES-1); - - // search the border bins as well - for (i=-1 ; i<=1 ; i++) - { - h = (hash+i)&(PLANE_HASHES-1); - for (p = planehash[h] ; p ; p=p->hash_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 ; i<b->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; i++) - { - s = b->original_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.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 ; k<b->numsides ; 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 ; l<w2->numpoints ; 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 ; i<ob->numsides ; i++) - { - plane = &mapplanes[ob->original_sides[i].planenum]; - w = BaseWindingForPlane (plane->normal, plane->dist); - for (j=0 ; j<ob->numsides && 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 ; j<w->numpoints ; 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 ; k<b->numsides ; 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 ; i<b->numsides ; 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 ; i<newbrushes ; i++) - temp[i].entitynum = 0; -#endif - - // make space to move the brushes (overlapped copy) - memmove (mapbrushes + worldbrushes + newbrushes, - mapbrushes + worldbrushes, - sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) ); - - // copy the new brushes down - memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes); - - // fix up indexes - entities[0].numbrushes += newbrushes; - for (i=1 ; i<num_entities ; i++) - entities[i].firstbrush += newbrushes; - free (temp); - - mapent->numbrushes = 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 ; i<mapent->numbrushes ; i++) - { - b = &mapbrushes[mapent->firstbrush + i]; - for (j=0 ; j<b->numsides ; 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<entities[0].numbrushes ; i++) - { - if (mapbrushes[i].mins[0] > 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 ; bn<nummapbrushes ; bn++) - { - brush = &mapbrushes[bn]; - fprintf (f, "{\n"); - for (i=0 ; i<brush->numsides ; 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"); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<nummapplanes ; i++, p++) + { + if (PlaneEqual (p, normal, dist)) + return i; + } + + return CreateNewFloatPlane (normal, dist); +} +#else +int FindFloatPlane (vec3_t normal, vec_t dist) +{ + int i; + plane_t *p; + int hash, h; + + SnapPlane (normal, &dist); + hash = (int)fabs(dist) / 8; + hash &= (PLANE_HASHES-1); + + // search the border bins as well + for (i=-1 ; i<=1 ; i++) + { + h = (hash+i)&(PLANE_HASHES-1); + for (p = planehash[h] ; p ; p=p->hash_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 ; i<b->numsides ; 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 ; i<b->numsides ; 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 ; i<b->numsides ; i++) + { + s = b->original_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.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 ; k<b->numsides ; 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 ; l<w2->numpoints ; 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 ; i<ob->numsides ; i++) + { + plane = &mapplanes[ob->original_sides[i].planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; j<ob->numsides && 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 ; j<w->numpoints ; 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 ; k<b->numsides ; 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 ; i<b->numsides ; 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 ; i<newbrushes ; i++) + temp[i].entitynum = 0; +#endif + + // make space to move the brushes (overlapped copy) + memmove (mapbrushes + worldbrushes + newbrushes, + mapbrushes + worldbrushes, + sizeof(mapbrush_t) * (nummapbrushes - worldbrushes - newbrushes) ); + + // copy the new brushes down + memcpy (mapbrushes + worldbrushes, temp, sizeof(mapbrush_t) * newbrushes); + + // fix up indexes + entities[0].numbrushes += newbrushes; + for (i=1 ; i<num_entities ; i++) + entities[i].firstbrush += newbrushes; + free (temp); + + mapent->numbrushes = 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 ; i<mapent->numbrushes ; i++) + { + b = &mapbrushes[mapent->firstbrush + i]; + for (j=0 ; j<b->numsides ; 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<entities[0].numbrushes ; i++) + { + if (mapbrushes[i].mins[0] > 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 ; bn<nummapbrushes ; bn++) + { + brush = &mapbrushes[bn]; + fprintf (f, "{\n"); + for (i=0 ; i<brush->numsides ; 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 index e3f3680b..e473fb34 100644 --- a/tools/quake2/q2map/nodraw.c +++ b/tools/quake2/q2map/nodraw.c @@ -1,46 +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) -{ -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index eb76bc39..8b9b75fb 100644 --- a/tools/quake2/q2map/patches.c +++ b/tools/quake2/q2map/patches.c @@ -1,603 +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 ; i<numtexinfo ; i++) - { - // see if an earlier texinfo allready got the value - for (j=0 ; j<i ; j++) - { - if (!strcmp (texinfo[i].texture, texinfo[j].texture)) - { - VectorCopy (texture_reflectivity[j], texture_reflectivity[i]); - break; - } - } - if (j != i) - continue; - - // load the wal file - sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture); - if (TryLoadFile (path, (void **)&mt) == -1) - { - Sys_Printf ("Couldn't load %s\n", path); - texture_reflectivity[i][0] = 0.5; - texture_reflectivity[i][1] = 0.5; - texture_reflectivity[i][2] = 0.5; - continue; - } - texels = LittleLong(mt->width)*LittleLong(mt->height); - color[0] = color[1] = color[2] = 0; - - for (j=0 ; j<texels ; j++) - { - texel = ((byte *)mt)[LittleLong(mt->offsets[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 ; i<numtexinfo ; i++) - { - // see if an earlier texinfo allready got the value - for (j=0 ; j<i ; j++) - { - if (!strcmp (texinfo[i].texture, texinfo[j].texture)) - { - VectorCopy (texture_reflectivity[j], texture_reflectivity[i]); - break; - } - } - if (j != i) - continue; - - // load the wal file - - sprintf (path, "%stextures/%s.m32", gamedir, texinfo[i].texture); - if (TryLoadFile (path, (void **)&mt32) == -1) - { - sprintf (path, "%stextures/%s.m8", gamedir, texinfo[i].texture); - if (TryLoadFile (path, (void **)&mt) == -1) - { - Sys_Printf ("Couldn't load %s\n", path); - texture_reflectivity[i][0] = 0.5; - texture_reflectivity[i][1] = 0.5; - texture_reflectivity[i][2] = 0.5; - continue; - } - texels = LittleLong(mt->width[0])*LittleLong(mt->height[0]); - color[0] = color[1] = color[2] = 0; - - for (j=0 ; j<texels ; j++) - { - texel = ((byte *)mt)[LittleLong(mt->offsets[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 ; j<texels ; j++) - { - pos = (byte *)mt32 + mt32->offsets[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 ; i<f->numedges ; 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 ; i<num_entities ; i++) - { - s = ValueForKey (&entities[i], "model"); - if (!strcmp (s, name)) - return &entities[i]; - } - - return &entities[0]; -} - -/* -============= -MakePatches -============= -*/ -void MakePatches (void) -{ - int i, j, k; - dface_t *f; - int fn; - winding_t *w; - dmodel_t *mod; - vec3_t origin; - entity_t *ent; - - Sys_FPrintf( SYS_VRB, "%i faces\n", numfaces); - - for (i=0 ; i<nummodels ; i++) - { - mod = &dmodels[i]; - ent = EntityForModel (i); - // bmodels with origin brushes need to be offset into their - // in-use position - GetVectorForKey (ent, "origin", origin); -//VectorCopy (vec3_origin, origin); - - for (j=0 ; j<mod->numfaces ; j++) - { - fn = mod->firstface + j; - face_entity[fn] = ent; - VectorCopy (origin, face_offset[fn]); - f = &dfaces[fn]; - w = WindingFromFace (f); - for (k=0 ; k<w->numpoints ; 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 ; i<w->numpoints ; 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<num ; i++) - { -// SubdividePatch (&patches[i]); - DicePatch (&patches[i]); - } - Sys_FPrintf( SYS_VRB, "%i patches after subdivision\n", num_patches); -} - -//===================================================================== +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<numtexinfo ; i++) + { + // see if an earlier texinfo allready got the value + for (j=0 ; j<i ; j++) + { + if (!strcmp (texinfo[i].texture, texinfo[j].texture)) + { + VectorCopy (texture_reflectivity[j], texture_reflectivity[i]); + break; + } + } + if (j != i) + continue; + + // load the wal file + sprintf (path, "%stextures/%s.wal", gamedir, texinfo[i].texture); + if (TryLoadFile (path, (void **)&mt) == -1) + { + Sys_Printf ("Couldn't load %s\n", path); + texture_reflectivity[i][0] = 0.5; + texture_reflectivity[i][1] = 0.5; + texture_reflectivity[i][2] = 0.5; + continue; + } + texels = LittleLong(mt->width)*LittleLong(mt->height); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; j<texels ; j++) + { + texel = ((byte *)mt)[LittleLong(mt->offsets[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 ; i<numtexinfo ; i++) + { + // see if an earlier texinfo allready got the value + for (j=0 ; j<i ; j++) + { + if (!strcmp (texinfo[i].texture, texinfo[j].texture)) + { + VectorCopy (texture_reflectivity[j], texture_reflectivity[i]); + break; + } + } + if (j != i) + continue; + + // load the wal file + + sprintf (path, "%stextures/%s.m32", gamedir, texinfo[i].texture); + if (TryLoadFile (path, (void **)&mt32) == -1) + { + sprintf (path, "%stextures/%s.m8", gamedir, texinfo[i].texture); + if (TryLoadFile (path, (void **)&mt) == -1) + { + Sys_Printf ("Couldn't load %s\n", path); + texture_reflectivity[i][0] = 0.5; + texture_reflectivity[i][1] = 0.5; + texture_reflectivity[i][2] = 0.5; + continue; + } + texels = LittleLong(mt->width[0])*LittleLong(mt->height[0]); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; j<texels ; j++) + { + texel = ((byte *)mt)[LittleLong(mt->offsets[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 ; j<texels ; j++) + { + pos = (byte *)mt32 + mt32->offsets[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 ; i<f->numedges ; 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 ; i<num_entities ; i++) + { + s = ValueForKey (&entities[i], "model"); + if (!strcmp (s, name)) + return &entities[i]; + } + + return &entities[0]; +} + +/* +============= +MakePatches +============= +*/ +void MakePatches (void) +{ + int i, j, k; + dface_t *f; + int fn; + winding_t *w; + dmodel_t *mod; + vec3_t origin; + entity_t *ent; + + Sys_FPrintf( SYS_VRB, "%i faces\n", numfaces); + + for (i=0 ; i<nummodels ; i++) + { + mod = &dmodels[i]; + ent = EntityForModel (i); + // bmodels with origin brushes need to be offset into their + // in-use position + GetVectorForKey (ent, "origin", origin); +//VectorCopy (vec3_origin, origin); + + for (j=0 ; j<mod->numfaces ; j++) + { + fn = mod->firstface + j; + face_entity[fn] = ent; + VectorCopy (origin, face_offset[fn]); + f = &dfaces[fn]; + w = WindingFromFace (f); + for (k=0 ; k<w->numpoints ; 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 ; i<w->numpoints ; 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<num ; i++) + { +// SubdividePatch (&patches[i]); + DicePatch (&patches[i]); + } + Sys_FPrintf( SYS_VRB, "%i patches after subdivision\n", num_patches); +} + +//===================================================================== diff --git a/tools/quake2/q2map/portals.c b/tools/quake2/q2map/portals.c index a65b66b2..9857a3ba 100644 --- a/tools/quake2/q2map/portals.c +++ b/tools/quake2/q2map/portals.c @@ -1,1110 +1,1110 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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_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 = 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 ; i<w->numpoints ; 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 ; i<p->winding->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 ; i<num_entities ; i++) - { - GetVectorForKey (&entities[i], "origin", origin); - if (VectorCompare(origin, vec3_origin)) - continue; - - cl = ValueForKey (&entities[i], "classname"); - origin[2] += 1; // so objects on floor are ok - - // nudge playerstart around if needed so clipping hulls allways - // have a vlaid point - if (!strcmp (cl, "info_player_start")) - { - int x, y; - - for (x=-16 ; x<=16 ; x += 16) - { - for (y=-16 ; y<=16 ; y += 16) - { - origin[0] += x; - origin[1] += y; - if (PlaceOccupant (headnode, origin, &entities[i])) - { - inside = true; - goto gotit; - } - origin[0] -= x; - origin[1] -= y; - } - } -gotit: ; - } - else - { - if (PlaceOccupant (headnode, origin, &entities[i])) - inside = true; - } - } - - 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 -============= -*/ -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 ; j<num_entities ; j++) - { - e = &entities[j]; - if (!e->areaportalnum) - 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 ; i<brush->numsides ; 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 ; i<endbrush ; i++) - { - mb = &mapbrushes[i]; - - numsides = mb->numsides; - for (j=0 ; j<numsides ; j++) - mb->original_sides[j].visible = false; - } - - // set visible flags on the sides that are used by portals - MarkVisibleSides_r (tree->headnode); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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_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 = 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 ; i<w->numpoints ; 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 ; i<p->winding->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 ; i<num_entities ; i++) + { + GetVectorForKey (&entities[i], "origin", origin); + if (VectorCompare(origin, vec3_origin)) + continue; + + cl = ValueForKey (&entities[i], "classname"); + origin[2] += 1; // so objects on floor are ok + + // nudge playerstart around if needed so clipping hulls allways + // have a vlaid point + if (!strcmp (cl, "info_player_start")) + { + int x, y; + + for (x=-16 ; x<=16 ; x += 16) + { + for (y=-16 ; y<=16 ; y += 16) + { + origin[0] += x; + origin[1] += y; + if (PlaceOccupant (headnode, origin, &entities[i])) + { + inside = true; + goto gotit; + } + origin[0] -= x; + origin[1] -= y; + } + } +gotit: ; + } + else + { + if (PlaceOccupant (headnode, origin, &entities[i])) + inside = true; + } + } + + 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 +============= +*/ +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 ; j<num_entities ; j++) + { + e = &entities[j]; + if (!e->areaportalnum) + 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 ; i<brush->numsides ; 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 ; i<endbrush ; i++) + { + mb = &mapbrushes[i]; + + numsides = mb->numsides; + for (j=0 ; j<numsides ; j++) + mb->original_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 index c88e039c..bfac302c 100644 --- a/tools/quake2/q2map/prtfile.c +++ b/tools/quake2/q2map/prtfile.c @@ -1,286 +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 ; i<w->numpoints ; 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 index 159232d8..7303263c 100644 --- a/tools/quake2/q2map/q2map.h +++ b/tools/quake2/q2map/q2map.h @@ -1,50 +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 <unistd.h> - #include <pwd.h> - #include <limits.h> -#endif - -#ifdef _WIN32 - #include <windows.h> -#endif - -#include <stdlib.h> - -#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 (); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <unistd.h> + #include <pwd.h> + #include <limits.h> +#endif + +#ifdef _WIN32 + #include <windows.h> +#endif + +#include <stdlib.h> + +#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/qbsp.c b/tools/quake2/q2map/qbsp.c index 84e4570c..4f1180da 100644 --- a/tools/quake2/q2map/qbsp.c +++ b/tools/quake2/q2map/qbsp.c @@ -1,426 +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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index ecfaa7ca..47d8d4b5 100644 --- a/tools/quake2/q2map/qbsp.h +++ b/tools/quake2/q2map/qbsp.h @@ -1,390 +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]; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e324c574..c204b56f 100644 --- a/tools/quake2/q2map/qrad.c +++ b/tools/quake2/q2map/qrad.c @@ -1,647 +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 ; i<numplanes ; i++) - { - backplanes[i].dist = -dplanes[i].dist; - VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal); - } -} - -int leafparents[MAX_MAP_LEAFS]; -int nodeparents[MAX_MAP_NODES]; - -/* -============= -MakeParents -============= -*/ -void MakeParents (int nodenum, int parent) -{ - int i, j; - dnode_t *node; - - nodeparents[nodenum] = parent; - node = &dnodes[nodenum]; - - for (i=0 ; i<2 ; i++) - { - j = node->children[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 ; j<num_patches ; j++, patch2++) - { - transfers[j] = 0; - - if (j == i) - continue; - - // check pvs bit - if (!nopvs) - { - cluster = patch2->cluster; - 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 ; j<num_patches ; j++) - { - if (transfers[j] <= 0) - continue; - itrans = transfers[j]*0x10000 / total; - itotal += itrans; - t->transfer = 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 ; i<num_patches ; i++) - { - free (patches[i].transfers); - patches[i].transfers = NULL; - } -} - - -//=================================================================== - -/* -============= -WriteWorld -============= -*/ -void WriteWorld (char *name) -{ - int i, j; - FILE *out; - patch_t *patch; - winding_t *w; - - out = fopen (name, "w"); - if (!out) - Error ("Couldn't open %s", name); - - for (j=0, patch=patches ; j<num_patches ; j++, patch++) - { - w = patch->winding; - fprintf (out, "%i\n", w->numpoints); - for (i=0 ; i<w->numpoints ; 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 ; j<num_patches ; j++) - { - p = &patches[j]; - w = p->winding; - fprintf (f, "%i\n", w->numpoints); - for (i=0 ; i<w->numpoints ; 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 ; i<num_patches ; i++, patch++) - { - // skys never collect light, it is just dropped - if (patch->sky) - { - 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 ; k<num ; k++, trans++) - { - for (l=0 ; l<3 ; l++) - illumination[trans->patch][l] += send[l]*trans->transfer; - } -} - -/* -============= -BounceLight -============= -*/ -void BounceLight (void) -{ - int i, j; - float added; - char name[64]; - patch_t *p; - - for (i=0 ; i<num_patches ; i++) - { - p = &patches[i]; - for (j=0 ; j<3 ; j++) - { -// p->totallight[j] = p->samplelight[j]; - radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area; - } - } - - for (i=0 ; i<numbounce ; i++) - { - RunThreadsOnIndividual (num_patches, false, ShootLight); - added = CollectLight (); - - Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added); - if ( dumppatches && (i==0 || i == numbounce-1) ) - { - sprintf (name, "bounce%i.txt", i); - WriteWorld (name); - } - } -} - - - -//============================================================== - -void CheckPatches (void) -{ - int i; - patch_t *patch; - - for (i=0 ; i<num_patches ; i++) - { - patch = &patches[i]; - if (patch->totallight[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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<numplanes ; i++) + { + backplanes[i].dist = -dplanes[i].dist; + VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal); + } +} + +int leafparents[MAX_MAP_LEAFS]; +int nodeparents[MAX_MAP_NODES]; + +/* +============= +MakeParents +============= +*/ +void MakeParents (int nodenum, int parent) +{ + int i, j; + dnode_t *node; + + nodeparents[nodenum] = parent; + node = &dnodes[nodenum]; + + for (i=0 ; i<2 ; i++) + { + j = node->children[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 ; j<num_patches ; j++, patch2++) + { + transfers[j] = 0; + + if (j == i) + continue; + + // check pvs bit + if (!nopvs) + { + cluster = patch2->cluster; + 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 ; j<num_patches ; j++) + { + if (transfers[j] <= 0) + continue; + itrans = transfers[j]*0x10000 / total; + itotal += itrans; + t->transfer = 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 ; i<num_patches ; i++) + { + free (patches[i].transfers); + patches[i].transfers = NULL; + } +} + + +//=================================================================== + +/* +============= +WriteWorld +============= +*/ +void WriteWorld (char *name) +{ + int i, j; + FILE *out; + patch_t *patch; + winding_t *w; + + out = fopen (name, "w"); + if (!out) + Error ("Couldn't open %s", name); + + for (j=0, patch=patches ; j<num_patches ; j++, patch++) + { + w = patch->winding; + fprintf (out, "%i\n", w->numpoints); + for (i=0 ; i<w->numpoints ; 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 ; j<num_patches ; j++) + { + p = &patches[j]; + w = p->winding; + fprintf (f, "%i\n", w->numpoints); + for (i=0 ; i<w->numpoints ; 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 ; i<num_patches ; i++, patch++) + { + // skys never collect light, it is just dropped + if (patch->sky) + { + 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 ; k<num ; k++, trans++) + { + for (l=0 ; l<3 ; l++) + illumination[trans->patch][l] += send[l]*trans->transfer; + } +} + +/* +============= +BounceLight +============= +*/ +void BounceLight (void) +{ + int i, j; + float added; + char name[64]; + patch_t *p; + + for (i=0 ; i<num_patches ; i++) + { + p = &patches[i]; + for (j=0 ; j<3 ; j++) + { +// p->totallight[j] = p->samplelight[j]; + radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area; + } + } + + for (i=0 ; i<numbounce ; i++) + { + RunThreadsOnIndividual (num_patches, false, ShootLight); + added = CollectLight (); + + Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added); + if ( dumppatches && (i==0 || i == numbounce-1) ) + { + sprintf (name, "bounce%i.txt", i); + WriteWorld (name); + } + } +} + + + +//============================================================== + +void CheckPatches (void) +{ + int i; + patch_t *patch; + + for (i=0 ; i<num_patches ; i++) + { + patch = &patches[i]; + if (patch->totallight[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 index 3bfc3854..2eef8bc4 100644 --- a/tools/quake2/q2map/qrad.h +++ b/tools/quake2/q2map/qrad.h @@ -1,184 +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 <windows.h> -#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]; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#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 index 30979914..bf7d3244 100644 --- a/tools/quake2/q2map/qvis.c +++ b/tools/quake2/q2map/qvis.c @@ -1,581 +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 ; i<w->numpoints ; 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 ; i<l->numportals ; 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<numportals*2 ; i++) - sorted_portals[i] = &portals[i]; - - if (nosort) - return; - qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp); -} - - -/* -============== -LeafVectorFromPortalVector -============== -*/ -int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits) -{ - int i; - portal_t *p; - int c_leafs; - - - memset (leafbits, 0, leafbytes); - - for (i=0 ; i<numportals*2 ; i++) - { - if (portalbits[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 ; i<leaf->numportals ; i++) - { - p = leaf->portals[i]; - if (p->status != stat_done) - Error ("portal not done"); - for (j=0 ; j<portallongs ; j++) - ((long *)portalvector)[j] |= ((long *)p->portalvis)[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 ; i<numportals*2 ; i++) - { - portals[i].portalvis = portals[i].portalflood; - portals[i].status = stat_done; - } - return; - } - - RunThreadsOnIndividual (numportals*2, true, PortalFlow); - -} - - -/* -================== -CalcVis -================== -*/ -void CalcVis (void) -{ - int i; - - RunThreadsOnIndividual (numportals*2, true, BasePortalVis); - -// RunThreadsOnIndividual (numportals*2, true, BetterPortalVis); - - SortPortals (); - - CalcPortalVis (); - -// -// assemble the leaf vis lists by oring and compressing the portal lists -// - for (i=0 ; i<portalclusters ; i++) - ClusterMerge (i); - - Sys_Printf ("Average clusters visible: %i\n", totalvis / portalclusters); -} - - -void SetPortalSphere (portal_t *p) -{ - int i; - vec3_t total, dist; - winding_t *w; - float r, bestr; - - w = p->winding; - VectorCopy (vec3_origin, total); - for (i=0 ; i<w->numpoints ; i++) - { - VectorAdd (total, w->points[i], total); - } - - for (i=0 ; i<3 ; i++) - total[i] /= w->numpoints; - - bestr = 0; - for (i=0 ; i<w->numpoints ; 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<numportals ; i++) - { - if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) - != 3) - Error ("LoadPortals: reading portal %i", i); - if (numpoints > 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 ; j<numpoints ; j++) - { - double v[3]; - int k; - - // scanf into double, then assign to vec_t - // so we don't care what size vec_t is - if (fscanf (f, "(%lf %lf %lf ) " - , &v[0], &v[1], &v[2]) != 3) - Error ("LoadPortals: reading portal %i", i); - for (k=0 ; k<3 ; k++) - w->points[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 ; j<w->numpoints ; 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 ; i++) - { - scan = uncompressedvis + i*leafbytes; - memcpy (uncompressed, scan, leafbytes); - for (j=0 ; j<leafbytes ; j++) - { - bitbyte = scan[j]; - if (!bitbyte) - continue; - for (k=0 ; k<8 ; k++) - { - if (! (bitbyte & (1<<k)) ) - continue; - // OR this pvs row into the phs - index = ((j<<3)+k); - if (index >= portalclusters) - Error ("Bad bit in PVS"); // pad bits should be 0 - src = (long *)(uncompressedvis + index*leafbytes); - dest = (long *)uncompressed; - for (l=0 ; l<leaflongs ; l++) - ((long *)uncompressed)[l] |= src[l]; - } - } - for (j=0 ; j<portalclusters ; j++) - if (uncompressed[j>>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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<l->numportals ; 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<numportals*2 ; i++) + sorted_portals[i] = &portals[i]; + + if (nosort) + return; + qsort (sorted_portals, numportals*2, sizeof(sorted_portals[0]), PComp); +} + + +/* +============== +LeafVectorFromPortalVector +============== +*/ +int LeafVectorFromPortalVector (byte *portalbits, byte *leafbits) +{ + int i; + portal_t *p; + int c_leafs; + + + memset (leafbits, 0, leafbytes); + + for (i=0 ; i<numportals*2 ; i++) + { + if (portalbits[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 ; i<leaf->numportals ; i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done"); + for (j=0 ; j<portallongs ; j++) + ((long *)portalvector)[j] |= ((long *)p->portalvis)[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 ; i<numportals*2 ; i++) + { + portals[i].portalvis = portals[i].portalflood; + portals[i].status = stat_done; + } + return; + } + + RunThreadsOnIndividual (numportals*2, true, PortalFlow); + +} + + +/* +================== +CalcVis +================== +*/ +void CalcVis (void) +{ + int i; + + RunThreadsOnIndividual (numportals*2, true, BasePortalVis); + +// RunThreadsOnIndividual (numportals*2, true, BetterPortalVis); + + SortPortals (); + + CalcPortalVis (); + +// +// assemble the leaf vis lists by oring and compressing the portal lists +// + for (i=0 ; i<portalclusters ; i++) + ClusterMerge (i); + + Sys_Printf ("Average clusters visible: %i\n", totalvis / portalclusters); +} + + +void SetPortalSphere (portal_t *p) +{ + int i; + vec3_t total, dist; + winding_t *w; + float r, bestr; + + w = p->winding; + VectorCopy (vec3_origin, total); + for (i=0 ; i<w->numpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; i<w->numpoints ; 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<numportals ; i++) + { + if (fscanf (f, "%i %i %i ", &numpoints, &leafnums[0], &leafnums[1]) + != 3) + Error ("LoadPortals: reading portal %i", i); + if (numpoints > 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 ; j<numpoints ; j++) + { + double v[3]; + int k; + + // scanf into double, then assign to vec_t + // so we don't care what size vec_t is + if (fscanf (f, "(%lf %lf %lf ) " + , &v[0], &v[1], &v[2]) != 3) + Error ("LoadPortals: reading portal %i", i); + for (k=0 ; k<3 ; k++) + w->points[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 ; j<w->numpoints ; 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 ; i++) + { + scan = uncompressedvis + i*leafbytes; + memcpy (uncompressed, scan, leafbytes); + for (j=0 ; j<leafbytes ; j++) + { + bitbyte = scan[j]; + if (!bitbyte) + continue; + for (k=0 ; k<8 ; k++) + { + if (! (bitbyte & (1<<k)) ) + continue; + // OR this pvs row into the phs + index = ((j<<3)+k); + if (index >= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l<leaflongs ; l++) + ((long *)uncompressed)[l] |= src[l]; + } + } + for (j=0 ; j<portalclusters ; j++) + if (uncompressed[j>>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 index 9128907c..44c84516 100644 --- a/tools/quake2/q2map/qvis.h +++ b/tools/quake2/q2map/qvis.h @@ -1,169 +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; +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index bbf6b29a..c0589de0 100644 --- a/tools/quake2/q2map/textures.c +++ b/tools/quake2/q2map/textures.c @@ -1,249 +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 ; i<nummiptex ; i++) - if (!strcmp (name, textureref[i].name)) - { - return i; - } - if (nummiptex == MAX_MAP_TEXTURES) - Error ("MAX_MAP_TEXTURES"); - strcpy (textureref[i].name, name); - - // load the miptex to get the flags and values - if ( !strcmp( game, "heretic2" ) ) - { - sprintf (path, "%stextures/%s.m32", gamedir, name); - if (TryLoadFile (path, (void **)&mt_m32) != -1) - { - textureref[i].value = LittleLong (mt_m32->value); - 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 ; i<numtexinfo ; i++, tc++) - { - if (tc->flags != 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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<nummiptex ; i++) + if (!strcmp (name, textureref[i].name)) + { + return i; + } + if (nummiptex == MAX_MAP_TEXTURES) + Error ("MAX_MAP_TEXTURES"); + strcpy (textureref[i].name, name); + + // load the miptex to get the flags and values + if ( !strcmp( game, "heretic2" ) ) + { + sprintf (path, "%stextures/%s.m32", gamedir, name); + if (TryLoadFile (path, (void **)&mt_m32) != -1) + { + textureref[i].value = LittleLong (mt_m32->value); + 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 ; i<numtexinfo ; i++, tc++) + { + if (tc->flags != 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 index 66d0e837..35902baf 100644 --- a/tools/quake2/q2map/trace.c +++ b/tools/quake2/q2map/trace.c @@ -1,298 +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]; - } -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index ec5b5b7c..6ca4aa16 100644 --- a/tools/quake2/q2map/tree.c +++ b/tools/quake2/q2map/tree.c @@ -1,218 +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 ; i<depth ; i++) - Sys_Printf (" "); - if (node->planenum == 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); -} - -//=========================================================== +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<depth ; i++) + Sys_Printf (" "); + if (node->planenum == 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 index 083f0ea7..8c45d530 100644 --- a/tools/quake2/q2map/writebsp.c +++ b/tools/quake2/q2map/writebsp.c @@ -1,591 +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 ; i<nummapplanes ; i++, mp++) - { - dp = &dplanes[numplanes]; - planetranslate[i] = numplanes; - VectorCopy ( mp->normal, 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<numleaffaces ; i++) - if (dleaffaces[i] == facenum) - break; // merged out face - if (i == numleaffaces) - { - if (numleaffaces >= 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 ; i<numleafbrushes ; i++) - if (dleafbrushes[i] == brushnum) - break; - if (i == numleafbrushes) - { - dleafbrushes[numleafbrushes] = brushnum; - numleafbrushes++; - } - } - leaf_p->numleafbrushes = 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 ; i<f->numpoints ; 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 ; i<num_entities ; i++) - { - if (entities[i].numbrushes) - { - sprintf (value, "*%i", models); - models++; - SetKeyValue (&entities[i], "model", value); - } - } - -} - -/* -============ -SetLightStyles -============ -*/ -#define MAX_SWITCHED_LIGHTS 32 -void SetLightStyles (void) -{ - int stylenum; - char *t; - entity_t *e; - int i, j; - char value[10]; - char lighttargets[MAX_SWITCHED_LIGHTS][64]; - - - // any light that is controlled (has a targetname) - // must have a unique style number generated for it - - stylenum = 0; - for (i=1 ; i<num_entities ; i++) - { - e = &entities[i]; - - t = ValueForKey (e, "classname"); - if (Q_strncasecmp (t, "light", 5)) - continue; - t = ValueForKey (e, "targetname"); - if (!t[0]) - continue; - - // find this targetname - for (j=0 ; j<stylenum ; j++) - if (!strcmp (lighttargets[j], t)) - break; - if (j == stylenum) - { - if (stylenum == MAX_SWITCHED_LIGHTS) - Error ("stylenum == MAX_SWITCHED_LIGHTS"); - strcpy (lighttargets[j], t); - stylenum++; - } - sprintf (value, "%i", 32 + j); - SetKeyValue (e, "style", value); - } - -} - -//=========================================================== - -/* -============ -EmitBrushes -============ -*/ -void EmitBrushes (void) -{ - int i, j, bnum, s, x; - dbrush_t *db; - mapbrush_t *b; - dbrushside_t *cp; - vec3_t normal; - vec_t dist; - int planenum; - - numbrushsides = 0; - numbrushes = nummapbrushes; - - for (bnum=0 ; bnum<nummapbrushes ; bnum++) - { - b = &mapbrushes[bnum]; - db = &dbrushes[bnum]; - - db->contents = b->contents; - db->firstside = numbrushsides; - db->numsides = b->numsides; - for (j=0 ; j<b->numsides ; 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 ; i<b->numsides ; 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 ; j<end ; j++) - { - b = &mapbrushes[j]; - if (!b->numsides) - 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++; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<nummapplanes ; i++, mp++) + { + dp = &dplanes[numplanes]; + planetranslate[i] = numplanes; + VectorCopy ( mp->normal, 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<numleaffaces ; i++) + if (dleaffaces[i] == facenum) + break; // merged out face + if (i == numleaffaces) + { + if (numleaffaces >= 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 ; i<numleafbrushes ; i++) + if (dleafbrushes[i] == brushnum) + break; + if (i == numleafbrushes) + { + dleafbrushes[numleafbrushes] = brushnum; + numleafbrushes++; + } + } + leaf_p->numleafbrushes = 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 ; i<f->numpoints ; 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 ; i<num_entities ; i++) + { + if (entities[i].numbrushes) + { + sprintf (value, "*%i", models); + models++; + SetKeyValue (&entities[i], "model", value); + } + } + +} + +/* +============ +SetLightStyles +============ +*/ +#define MAX_SWITCHED_LIGHTS 32 +void SetLightStyles (void) +{ + int stylenum; + char *t; + entity_t *e; + int i, j; + char value[10]; + char lighttargets[MAX_SWITCHED_LIGHTS][64]; + + + // any light that is controlled (has a targetname) + // must have a unique style number generated for it + + stylenum = 0; + for (i=1 ; i<num_entities ; i++) + { + e = &entities[i]; + + t = ValueForKey (e, "classname"); + if (Q_strncasecmp (t, "light", 5)) + continue; + t = ValueForKey (e, "targetname"); + if (!t[0]) + continue; + + // find this targetname + for (j=0 ; j<stylenum ; j++) + if (!strcmp (lighttargets[j], t)) + break; + if (j == stylenum) + { + if (stylenum == MAX_SWITCHED_LIGHTS) + Error ("stylenum == MAX_SWITCHED_LIGHTS"); + strcpy (lighttargets[j], t); + stylenum++; + } + sprintf (value, "%i", 32 + j); + SetKeyValue (e, "style", value); + } + +} + +//=========================================================== + +/* +============ +EmitBrushes +============ +*/ +void EmitBrushes (void) +{ + int i, j, bnum, s, x; + dbrush_t *db; + mapbrush_t *b; + dbrushside_t *cp; + vec3_t normal; + vec_t dist; + int planenum; + + numbrushsides = 0; + numbrushes = nummapbrushes; + + for (bnum=0 ; bnum<nummapbrushes ; bnum++) + { + b = &mapbrushes[bnum]; + db = &dbrushes[bnum]; + + db->contents = b->contents; + db->firstside = numbrushsides; + db->numsides = b->numsides; + for (j=0 ; j<b->numsides ; 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 ; i<b->numsides ; 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 ; j<end ; j++) + { + b = &mapbrushes[j]; + if (!b->numsides) + 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 index caddaa0c..65170ad9 100644 --- a/tools/quake2/qdata/anorms.h +++ b/tools/quake2/qdata/anorms.h @@ -1,162 +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 }, + { -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 index e3b8fc1b..37a2fc19 100644 --- a/tools/quake2/qdata/images.c +++ b/tools/quake2/qdata/images.c @@ -1,742 +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 ; i<c ; i++) - if (pixels[i] == 0) - pixels[i] = alt_zero; -} - -/* -============== -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 (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; - } - - GetToken (false); - xl = atoi (token); - GetToken (false); - yl = atoi (token); - GetToken (false); - w = atoi (token); - GetToken (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 = malloc (w*h); - for (y=0 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, w, h, lbmpalette); - - free (cropped); -} - -/* -============== -Cmd_Raw - -$grab filename x y width height -============== -*/ -void Cmd_Raw (void) -{ - int xl,yl,w,h,y; - byte *cropped; - char savename[1024]; - char dest[1024]; - - GetToken (false); - - sprintf (savename, "%s%s.lmp", gamedir, token); - - if (g_release) - { - sprintf (dest, "%s.lmp", token); - ReleaseFile (dest); - return; - } - - GetToken (false); - xl = atoi (token); - GetToken (false); - yl = atoi (token); - GetToken (false); - w = atoi (token); - GetToken (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 = malloc (w*h); - for (y=0 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - - SaveFile (savename, cropped, w*h); - - free (cropped); -} - -/* -============================================================================= - -COLORMAP GRABBING - -============================================================================= -*/ - -/* -=============== -BestColor -=============== -*/ -byte BestColor (int r, int g, int b, int start, int stop) -{ - int i; - int dr, dg, db; - int bestdistortion, distortion; - int bestcolor; - byte *pal; - -// -// let any color go to 0 as a last resort -// - bestdistortion = 256*256*4; - bestcolor = 0; - - pal = colormap_palette + start*3; - for (i=start ; i<= stop ; i++) - { - dr = r - (int)pal[0]; - dg = g - (int)pal[1]; - db = b - (int)pal[2]; - pal += 3; - distortion = dr*dr + dg*dg + db*db; - if (distortion < bestdistortion) - { - if (!distortion) - return i; // perfect match - - bestdistortion = distortion; - bestcolor = i; - } - } - - return bestcolor; -} - - -/* -============== -Cmd_Colormap - -$colormap filename - - the brightes colormap is first in the table (FIXME: reverse this now?) - - 64 rows of 256 : lightmaps - 256 rows of 256 : translucency table -============== -*/ -void Cmd_Colormap (void) -{ - int levels, brights; - int l, c; - float frac, red, green, blue; - float range; - byte *cropped, *lump_p; - char savename[1024]; - char dest[1024]; - - colormap_issued = true; - if (!g_release) - memcpy (colormap_palette, lbmpalette, 768); - - if (!TokenAvailable ()) - { // just setting colormap_issued - return; - } - - GetToken (false); - sprintf (savename, "%spics/%s.pcx", gamedir, token); - - if (g_release) - { - sprintf (dest, "pics/%s.pcx", token); - ReleaseFile (dest); - return; - } - - range = 2; - levels = 64; - brights = 1; // ignore 255 (transparent) - - cropped = malloc((levels+256)*256); - lump_p = cropped; - -// shaded levels - for (l=0;l<levels;l++) - { - frac = range - range*(float)l/(levels-1); - for (c=0 ; c<256-brights ; c++) - { - red = lbmpalette[c*3]; - green = lbmpalette[c*3+1]; - blue = lbmpalette[c*3+2]; - - red = (int)(red*frac+0.5); - green = (int)(green*frac+0.5); - blue = (int)(blue*frac+0.5); - -// -// note: 254 instead of 255 because 255 is the transparent color, and we -// don't want anything remapping to that -// don't use color 0, because NT can't remap that (or 255) -// - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - - // fullbrights allways stay the same - for ( ; c<256 ; c++) - *lump_p++ = c; - } - -// 66% transparancy table - for (l=0;l<255;l++) - { - for (c=0 ; c<255 ; c++) - { - red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; - green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; - blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; - - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - *lump_p++ = 255; - } - for (c=0 ; c<256 ; c++) - *lump_p++ = 255; - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); - - free (cropped); -} - -/* -============================================================================= - -MIPTEX GRABBING - -============================================================================= -*/ - -byte pixdata[256]; - -int d_red, d_green, d_blue; - -byte palmap[32][32][32]; -qboolean palmap_built; - -/* -============= -FindColor -============= -*/ -int FindColor (int r, int g, int b) -{ - int bestcolor; - - if (r > 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<count ; i++) - { - pix = pixdata[i]; - - r += lbmpalette[pix*3]; - g += lbmpalette[pix*3+1]; - b += lbmpalette[pix*3+2]; - vis++; - } - - r /= vis; - g /= vis; - b /= vis; - - // error diffusion - r += d_red; - g += d_green; - b += d_blue; - -// -// find the best color -// - bestcolor = FindColor (r, g, b); - - // error diffusion - pal = colormap_palette + bestcolor*3; - d_red = r - (int)pal[0]; - d_green = g - (int)pal[1]; - d_blue = b - (int)pal[2]; - - return bestcolor; -} - - -typedef enum -{ - pt_contents, - pt_flags, - pt_animvalue, - pt_flagvalue -} parmtype_t; - -typedef struct -{ - char *name; - int flags; - parmtype_t type; -} mipparm_t; - -mipparm_t mipparms[] = -{ - // utility content attributes - {"water", CONTENTS_WATER, pt_contents}, - {"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging - {"lava", CONTENTS_LAVA, pt_contents}, // very damaging - {"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures - {"mist", CONTENTS_MIST, pt_contents}, // non-solid window - {"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes - {"playerclip", CONTENTS_PLAYERCLIP, pt_contents}, - {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents}, - - // utility surface attributes - {"hint", SURF_HINT, pt_flags}, - {"skip", SURF_SKIP, pt_flags}, - {"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity - - // texture chaining - {"anim", 0, pt_animvalue}, // value is the next animation - - // server attributes - {"slick", SURF_SLICK, pt_flags}, - - // drawing attributes - {"sky", SURF_SKY, pt_flags}, - {"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures - {"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright - {"trans66", SURF_TRANS66, pt_flags}, - {"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0 - {"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures - - {NULL, 0, pt_contents} -}; - - - -/* -============== -Cmd_Mip - -$mip filename x y width height <OPTIONS> -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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - pix = *screen_p++; - if (pix == 255) - pix = 1; // should never happen - *lump_p++ = pix; - } - screen_p += linedelta; - } - -// -// subsample for greater mip levels -// - d_red = d_green = d_blue = 0; // no distortion yet - - for (miplevel = 1 ; miplevel<4 ; miplevel++) - { - qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex); - - mipstep = 1<<miplevel; - for (y=0 ; y<h ; y+=mipstep) - { - - for (x = 0 ; x<w ; x+= mipstep) - { - count = 0; - for (yy=0 ; yy<mipstep ; yy++) - for (xx=0 ; xx<mipstep ; xx++) - { - pixdata[count] = source[ (y+yy)*w + x + xx ]; - count++; - } - *lump_p++ = AveragePixels (count); - } - } - } - -// -// dword align the size -// - while ((int)lump_p&3) - *lump_p++ = 0; - -// -// write it out -// - printf ("writing %s\n", filename); - SaveFile (filename, (byte *)qtex, lump_p - (byte *)qtex); - - 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]; - - GetToken (false); - strcpy (mip_prefix, token); - // create the directory if needed - sprintf (filename, "%stextures", gamedir, mip_prefix); - Q_mkdir (filename); - sprintf (filename, "%stextures/%s", gamedir, 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; - - GetToken (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); - } -} - +#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 ; i<c ; i++) + if (pixels[i] == 0) + pixels[i] = alt_zero; +} + +/* +============== +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 (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; + } + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (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 = malloc (w*h); + for (y=0 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, w, h, lbmpalette); + + free (cropped); +} + +/* +============== +Cmd_Raw + +$grab filename x y width height +============== +*/ +void Cmd_Raw (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetToken (false); + + sprintf (savename, "%s%s.lmp", gamedir, token); + + if (g_release) + { + sprintf (dest, "%s.lmp", token); + ReleaseFile (dest); + return; + } + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (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 = malloc (w*h); + for (y=0 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + + SaveFile (savename, cropped, w*h); + + free (cropped); +} + +/* +============================================================================= + +COLORMAP GRABBING + +============================================================================= +*/ + +/* +=============== +BestColor +=============== +*/ +byte BestColor (int r, int g, int b, int start, int stop) +{ + int i; + int dr, dg, db; + int bestdistortion, distortion; + int bestcolor; + byte *pal; + +// +// let any color go to 0 as a last resort +// + bestdistortion = 256*256*4; + bestcolor = 0; + + pal = colormap_palette + start*3; + for (i=start ; i<= stop ; i++) + { + dr = r - (int)pal[0]; + dg = g - (int)pal[1]; + db = b - (int)pal[2]; + pal += 3; + distortion = dr*dr + dg*dg + db*db; + if (distortion < bestdistortion) + { + if (!distortion) + return i; // perfect match + + bestdistortion = distortion; + bestcolor = i; + } + } + + return bestcolor; +} + + +/* +============== +Cmd_Colormap + +$colormap filename + + the brightes colormap is first in the table (FIXME: reverse this now?) + + 64 rows of 256 : lightmaps + 256 rows of 256 : translucency table +============== +*/ +void Cmd_Colormap (void) +{ + int levels, brights; + int l, c; + float frac, red, green, blue; + float range; + byte *cropped, *lump_p; + char savename[1024]; + char dest[1024]; + + colormap_issued = true; + if (!g_release) + memcpy (colormap_palette, lbmpalette, 768); + + if (!TokenAvailable ()) + { // just setting colormap_issued + return; + } + + GetToken (false); + sprintf (savename, "%spics/%s.pcx", gamedir, token); + + if (g_release) + { + sprintf (dest, "pics/%s.pcx", token); + ReleaseFile (dest); + return; + } + + range = 2; + levels = 64; + brights = 1; // ignore 255 (transparent) + + cropped = malloc((levels+256)*256); + lump_p = cropped; + +// shaded levels + for (l=0;l<levels;l++) + { + frac = range - range*(float)l/(levels-1); + for (c=0 ; c<256-brights ; c++) + { + red = lbmpalette[c*3]; + green = lbmpalette[c*3+1]; + blue = lbmpalette[c*3+2]; + + red = (int)(red*frac+0.5); + green = (int)(green*frac+0.5); + blue = (int)(blue*frac+0.5); + +// +// note: 254 instead of 255 because 255 is the transparent color, and we +// don't want anything remapping to that +// don't use color 0, because NT can't remap that (or 255) +// + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + + // fullbrights allways stay the same + for ( ; c<256 ; c++) + *lump_p++ = c; + } + +// 66% transparancy table + for (l=0;l<255;l++) + { + for (c=0 ; c<255 ; c++) + { + red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; + green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; + blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; + + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + *lump_p++ = 255; + } + for (c=0 ; c<256 ; c++) + *lump_p++ = 255; + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); + + free (cropped); +} + +/* +============================================================================= + +MIPTEX GRABBING + +============================================================================= +*/ + +byte pixdata[256]; + +int d_red, d_green, d_blue; + +byte palmap[32][32][32]; +qboolean palmap_built; + +/* +============= +FindColor +============= +*/ +int FindColor (int r, int g, int b) +{ + int bestcolor; + + if (r > 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<count ; i++) + { + pix = pixdata[i]; + + r += lbmpalette[pix*3]; + g += lbmpalette[pix*3+1]; + b += lbmpalette[pix*3+2]; + vis++; + } + + r /= vis; + g /= vis; + b /= vis; + + // error diffusion + r += d_red; + g += d_green; + b += d_blue; + +// +// find the best color +// + bestcolor = FindColor (r, g, b); + + // error diffusion + pal = colormap_palette + bestcolor*3; + d_red = r - (int)pal[0]; + d_green = g - (int)pal[1]; + d_blue = b - (int)pal[2]; + + return bestcolor; +} + + +typedef enum +{ + pt_contents, + pt_flags, + pt_animvalue, + pt_flagvalue +} parmtype_t; + +typedef struct +{ + char *name; + int flags; + parmtype_t type; +} mipparm_t; + +mipparm_t mipparms[] = +{ + // utility content attributes + {"water", CONTENTS_WATER, pt_contents}, + {"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging + {"lava", CONTENTS_LAVA, pt_contents}, // very damaging + {"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures + {"mist", CONTENTS_MIST, pt_contents}, // non-solid window + {"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes + {"playerclip", CONTENTS_PLAYERCLIP, pt_contents}, + {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents}, + + // utility surface attributes + {"hint", SURF_HINT, pt_flags}, + {"skip", SURF_SKIP, pt_flags}, + {"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity + + // texture chaining + {"anim", 0, pt_animvalue}, // value is the next animation + + // server attributes + {"slick", SURF_SLICK, pt_flags}, + + // drawing attributes + {"sky", SURF_SKY, pt_flags}, + {"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures + {"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright + {"trans66", SURF_TRANS66, pt_flags}, + {"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0 + {"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures + + {NULL, 0, pt_contents} +}; + + + +/* +============== +Cmd_Mip + +$mip filename x y width height <OPTIONS> +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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + pix = *screen_p++; + if (pix == 255) + pix = 1; // should never happen + *lump_p++ = pix; + } + screen_p += linedelta; + } + +// +// subsample for greater mip levels +// + d_red = d_green = d_blue = 0; // no distortion yet + + for (miplevel = 1 ; miplevel<4 ; miplevel++) + { + qtex->offsets[miplevel] = LittleLong(lump_p - (byte *)qtex); + + mipstep = 1<<miplevel; + for (y=0 ; y<h ; y+=mipstep) + { + + for (x = 0 ; x<w ; x+= mipstep) + { + count = 0; + for (yy=0 ; yy<mipstep ; yy++) + for (xx=0 ; xx<mipstep ; xx++) + { + pixdata[count] = source[ (y+yy)*w + x + xx ]; + count++; + } + *lump_p++ = AveragePixels (count); + } + } + } + +// +// dword align the size +// + while ((int)lump_p&3) + *lump_p++ = 0; + +// +// write it out +// + printf ("writing %s\n", filename); + SaveFile (filename, (byte *)qtex, lump_p - (byte *)qtex); + + 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]; + + GetToken (false); + strcpy (mip_prefix, token); + // create the directory if needed + sprintf (filename, "%stextures", gamedir, mip_prefix); + Q_mkdir (filename); + sprintf (filename, "%stextures/%s", gamedir, 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; + + GetToken (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/models.c b/tools/quake2/qdata/models.c index 58fdc0ff..76713a5b 100644 --- a/tools/quake2/qdata/models.c +++ b/tools/quake2/qdata/models.c @@ -1,1132 +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 ; i<sizeof(dmdl_t)/4 ; i++) - ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); - - SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); - - // - // write out the skin names - // - SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); - - // - // write out the texture coordinates - // - c_on = c_off = 0; - for (i=0 ; i<model.num_st ; i++) - { - base_st[i].s = LittleShort (base_st[i].s); - base_st[i].t = LittleShort (base_st[i].t); - } - - SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); - - // - // write out the triangles - // - for (i=0 ; i<model.num_tris ; i++) - { - int j; - dtriangle_t tri; - - for (j=0 ; j<3 ; j++) - { - tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); - tri.index_st[j] = LittleShort (triangles[i].index_st[j]); - } - - SafeWrite (modelouthandle, &tri, sizeof(tri)); - } - - // - // write out the frames - // - for (i=0 ; i<model.num_frames ; i++) - { - in = &g_frames[i]; - out = (daliasframe_t *)buffer; - - strcpy (out->name, 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 ; j<model.num_xyz ; j++) - { - // all of these are byte values, so no need to deal with endianness - out->verts[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 ; i<model.num_skins ; i++) - { - ReleaseFile (g_skins[i]); - } - model.num_frames = 0; - return; - } - -// -// write the model output file -// - if (modelname[0]) - sprintf (name, "%s%s", gamedir, modelname); - else - sprintf (name, "%s/tris.md2", cddir); - printf ("saving to %s\n", name); - CreatePath (name); - modelouthandle = SafeOpenWrite (name); - - WriteModelFile (modelouthandle); - - printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight); - printf ("%4d vertexes\n", model.num_xyz); - printf ("%4d triangles\n", model.num_tris); - printf ("%4d frame\n", model.num_frames); - printf ("%4d glverts\n", numglverts); - printf ("%4d glcmd\n", model.num_glcmds); - printf ("%4d skins\n", model.num_skins); - printf ("file size: %d\n", (int)ftell (modelouthandle) ); - printf ("---------------------\n"); - - 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); - - fclose (headerouthandle); - headerouthandle = NULL; -} - - -/* -================================================================= - -ALIAS MODEL DISPLAY LIST GENERATION - -================================================================= -*/ - -int strip_xyz[128]; -int strip_st[128]; -int strip_tris[128]; -int stripcount; - -/* -================ -StripLength -================ -*/ -int StripLength (int starttri, int startv) -{ - int m1, m2; - int st1, st2; - int j; - dtriangle_t *last, *check; - int k; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) - { - 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]) - 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 ; j<model.num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - -/* -=========== -FanLength -=========== -*/ -int FanLength (int starttri, int startv) -{ - int m1, m2; - int st1, st2; - int j; - dtriangle_t *last, *check; - int k; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) - { - 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]) - 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<model.num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - - -/* -================ -BuildGlCmds - -Generate a list of trifans or strips -for the model, which holds for all frames -================ -*/ -void BuildGlCmds (void) -{ - int i, j, k; - int startv; - float s, t; - int len, bestlen, besttype; - int best_xyz[1024]; - int best_st[1024]; - int best_tris[1024]; - int type; - - // - // build tristrips - // - numcommands = 0; - numglverts = 0; - memset (used, 0, sizeof(used)); - for (i=0 ; i<model.num_tris ; i++) - { - // pick an unused triangle and start the trifan - if (used[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); - else - len = FanLength (i, startv); - if (len > bestlen) - { - besttype = type; - bestlen = len; - for (j=0 ; j<bestlen+2 ; j++) - { - best_st[j] = strip_st[j]; - best_xyz[j] = strip_xyz[j]; - } - for (j=0 ; j<bestlen ; j++) - best_tris[j] = strip_tris[j]; - } - } - } - - // mark the tris on the best strip/fan as used - for (j=0 ; j<bestlen ; j++) - used[best_tris[j]] = 1; - - if (besttype == 1) - commands[numcommands++] = (bestlen+2); - else - commands[numcommands++] = -(bestlen+2); - - numglverts += bestlen+2; - - for (j=0 ; j<bestlen+2 ; j++) - { - // emit a vertex into the reorder buffer - k = best_st[j]; - - // emit s/t coords into the commands stream - s = base_st[k].s; - t = base_st[k].t; - - s = (s + 0.5) / model.skinwidth; - t = (t + 0.5) / model.skinheight; - - *(float *)&commands[numcommands++] = s; - *(float *)&commands[numcommands++] = t; - *(int *)&commands[numcommands++] = best_xyz[j]; - } - } - - commands[numcommands++] = 0; // end of list marker -} - - -/* -=============================================================== - -BASE FRAME SETUP - -=============================================================== -*/ - -/* -============ -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) -{ - int i, j; - int width, height, iwidth, iheight, swidth; - float basex, basey; - float s_scale, t_scale; - float scale; - vec3_t mins, maxs; - float *pbasevert; - vec3_t vtemp1, vtemp2, normal; - - // - // find bounds of all the verts on the base frame - // - ClearBounds (mins, maxs); - - for (i=0 ; i<numtri ; i++) - for (j=0 ; j<3 ; j++) - AddPointToBounds (ptri[i].verts[j], mins, maxs); - - for (i=0 ; i<3 ; i++) - { - mins[i] = floor(mins[i]); - maxs[i] = ceil(maxs[i]); - } - - width = maxs[0] - mins[0]; - height = maxs[2] - mins[2]; - - 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<numtri ; i++) - { - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - if (normal[1] > 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<model.num_tris ; i++) - { - for (j=0 ; j<3 ; j++) - { - // get the xyz index - for (k=0 ; k<model.num_xyz ; k++) - if (VectorCompare (ptri[i].verts[j], base_xyz[k])) - break; // this vertex is already in the base vertex list - - if (k == model.num_xyz) - { // new index - VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]); - model.num_xyz++; - } - - triangles[i].index_xyz[j] = k; - - // get the st index - for (k=0 ; k<model.num_st ; k++) - if (triangle_st[i][j][0] == base_st[k].s - && triangle_st[i][j][1] == base_st[k].t) - break; // this vertex is already in the base vertex list - - if (k == model.num_st) - { // new index - base_st[model.num_st].s = triangle_st[i][j][0]; - base_st[model.num_st].t = triangle_st[i][j][1]; - model.num_st++; - } - - triangles[i].index_st[j] = k; - } - } - - // build triangle strips / fans - BuildGlCmds (); -} - -//=============================================================== - -char *FindFrameFile (char *frame) -{ - int time1; - char file1[1024]; - static char retname[1024]; - char base[32]; - char suffix[32]; - 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.%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 ; i<model.num_xyz ; i++) - { - vnorms[i].numnormals = 0; - VectorClear (vnorms[i].normalsum); - } - ClearBounds (fr->mins, 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 ; i<num_tris ; i++) - { - vec3_t vtemp1, vtemp2, normal; - float ftemp; - - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - VectorNormalize (normal, normal); - - // rotate the normal so the model faces down the positive x axis - ftemp = normal[0]; - normal[0] = -normal[1]; - normal[1] = ftemp; - - for (j=0 ; j<3 ; j++) - { - index_xyz = triangles[i].index_xyz[j]; - - // rotate the vertices so the model faces down the positive x axis - // also adjust the vertices to the desired origin - ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + - adjust[0]; - ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + - adjust[1]; - ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + - adjust[2]; - - AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<model.num_xyz ; i++) - { - int j; - vec3_t v; - float maxdot; - int maxdotindex; - int c; - - c = vnorms[i].numnormals; - if (!c) - Error ("Vertex with no triangles attached"); - - VectorScale (vnorms[i].normalsum, 1.0/c, v); - VectorNormalize (v, v); - - maxdot = -999999.0; - maxdotindex = -1; - - for (j=0 ; j<NUMVERTEXNORMALS ; j++) - { - float dot; - - dot = DotProduct (v, avertexnormals[j]); - if (dot > 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<model.skinheight ; y++) - { - memcpy (cropped+y*model.skinwidth, - pixels+y*width, model.skinwidth); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, model.skinwidth, - model.skinheight, palette); - - free (pixels); - free (palette); - free (cropped); -} - - -/* -================= -Cmd_Origin -================= -*/ -void Cmd_Origin (void) -{ - // rotate points into frame of reference so model points down the - // positive x axis - GetToken (false); - adjust[1] = -atof (token); - - GetToken (false); - adjust[0] = atof (token); - - GetToken (false); - adjust[2] = -atof (token); -} - - -/* -================= -Cmd_ScaleUp -================= -*/ -void Cmd_ScaleUp (void) -{ - GetToken (false); - scale_up = atof (token); - if (g_skipmodel || g_release || g_archive) - return; - - printf ("Scale up: %f\n", scale_up); -} - - -/* -================= -Cmd_Skinsize - -Set a skin size other than the default -================= -*/ -void Cmd_Skinsize (void) -{ - GetToken (false); - g_fixedwidth = atoi(token); - GetToken (false); - g_fixedheight = atoi(token); -} - -/* -================= -Cmd_Modelname - -Gives a different name/location for the file, instead of the cddir -================= -*/ -void Cmd_Modelname (void) -{ - GetToken (false); - strcpy (modelname, token); -} - -/* -=============== -Cmd_Cd -=============== -*/ -void Cmd_Cd (void) -{ - FinishModel (); - ClearModel (); - - GetToken (false); - - // this is a silly mess... - sprintf (cdpartial, "models/%s", token); - sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); - sprintf (cddir, "%s%s", gamedir, cdpartial); - - // 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 monsters) - if (!g_only[0]) - return; - if (strncmp(token, g_only, strlen(g_only))) - { - g_skipmodel = true; - printf ("skipping %s\n", cdpartial); - } -} - + +#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 ; i<sizeof(dmdl_t)/4 ; i++) + ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); + + SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); + + // + // write out the skin names + // + SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); + + // + // write out the texture coordinates + // + c_on = c_off = 0; + for (i=0 ; i<model.num_st ; i++) + { + base_st[i].s = LittleShort (base_st[i].s); + base_st[i].t = LittleShort (base_st[i].t); + } + + SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); + + // + // write out the triangles + // + for (i=0 ; i<model.num_tris ; i++) + { + int j; + dtriangle_t tri; + + for (j=0 ; j<3 ; j++) + { + tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); + tri.index_st[j] = LittleShort (triangles[i].index_st[j]); + } + + SafeWrite (modelouthandle, &tri, sizeof(tri)); + } + + // + // write out the frames + // + for (i=0 ; i<model.num_frames ; i++) + { + in = &g_frames[i]; + out = (daliasframe_t *)buffer; + + strcpy (out->name, 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 ; j<model.num_xyz ; j++) + { + // all of these are byte values, so no need to deal with endianness + out->verts[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 ; i<model.num_skins ; i++) + { + ReleaseFile (g_skins[i]); + } + model.num_frames = 0; + return; + } + +// +// write the model output file +// + if (modelname[0]) + sprintf (name, "%s%s", gamedir, modelname); + else + sprintf (name, "%s/tris.md2", cddir); + printf ("saving to %s\n", name); + CreatePath (name); + modelouthandle = SafeOpenWrite (name); + + WriteModelFile (modelouthandle); + + printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight); + printf ("%4d vertexes\n", model.num_xyz); + printf ("%4d triangles\n", model.num_tris); + printf ("%4d frame\n", model.num_frames); + printf ("%4d glverts\n", numglverts); + printf ("%4d glcmd\n", model.num_glcmds); + printf ("%4d skins\n", model.num_skins); + printf ("file size: %d\n", (int)ftell (modelouthandle) ); + printf ("---------------------\n"); + + 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); + + fclose (headerouthandle); + headerouthandle = NULL; +} + + +/* +================================================================= + +ALIAS MODEL DISPLAY LIST GENERATION + +================================================================= +*/ + +int strip_xyz[128]; +int strip_st[128]; +int strip_tris[128]; +int stripcount; + +/* +================ +StripLength +================ +*/ +int StripLength (int starttri, int startv) +{ + int m1, m2; + int st1, st2; + int j; + dtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) + { + 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]) + 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 ; j<model.num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + +/* +=========== +FanLength +=========== +*/ +int FanLength (int starttri, int startv) +{ + int m1, m2; + int st1, st2; + int j; + dtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) + { + 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]) + 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<model.num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + + +/* +================ +BuildGlCmds + +Generate a list of trifans or strips +for the model, which holds for all frames +================ +*/ +void BuildGlCmds (void) +{ + int i, j, k; + int startv; + float s, t; + int len, bestlen, besttype; + int best_xyz[1024]; + int best_st[1024]; + int best_tris[1024]; + int type; + + // + // build tristrips + // + numcommands = 0; + numglverts = 0; + memset (used, 0, sizeof(used)); + for (i=0 ; i<model.num_tris ; i++) + { + // pick an unused triangle and start the trifan + if (used[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); + else + len = FanLength (i, startv); + if (len > bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j<bestlen+2 ; j++) + { + best_st[j] = strip_st[j]; + best_xyz[j] = strip_xyz[j]; + } + for (j=0 ; j<bestlen ; j++) + best_tris[j] = strip_tris[j]; + } + } + } + + // mark the tris on the best strip/fan as used + for (j=0 ; j<bestlen ; j++) + used[best_tris[j]] = 1; + + if (besttype == 1) + commands[numcommands++] = (bestlen+2); + else + commands[numcommands++] = -(bestlen+2); + + numglverts += bestlen+2; + + for (j=0 ; j<bestlen+2 ; j++) + { + // emit a vertex into the reorder buffer + k = best_st[j]; + + // emit s/t coords into the commands stream + s = base_st[k].s; + t = base_st[k].t; + + s = (s + 0.5) / model.skinwidth; + t = (t + 0.5) / model.skinheight; + + *(float *)&commands[numcommands++] = s; + *(float *)&commands[numcommands++] = t; + *(int *)&commands[numcommands++] = best_xyz[j]; + } + } + + commands[numcommands++] = 0; // end of list marker +} + + +/* +=============================================================== + +BASE FRAME SETUP + +=============================================================== +*/ + +/* +============ +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) +{ + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float s_scale, t_scale; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + + for (i=0 ; i<numtri ; i++) + for (j=0 ; j<3 ; j++) + AddPointToBounds (ptri[i].verts[j], mins, maxs); + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + 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<numtri ; i++) + { + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + if (normal[1] > 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<model.num_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + // get the xyz index + for (k=0 ; k<model.num_xyz ; k++) + if (VectorCompare (ptri[i].verts[j], base_xyz[k])) + break; // this vertex is already in the base vertex list + + if (k == model.num_xyz) + { // new index + VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]); + model.num_xyz++; + } + + triangles[i].index_xyz[j] = k; + + // get the st index + for (k=0 ; k<model.num_st ; k++) + if (triangle_st[i][j][0] == base_st[k].s + && triangle_st[i][j][1] == base_st[k].t) + break; // this vertex is already in the base vertex list + + if (k == model.num_st) + { // new index + base_st[model.num_st].s = triangle_st[i][j][0]; + base_st[model.num_st].t = triangle_st[i][j][1]; + model.num_st++; + } + + triangles[i].index_st[j] = k; + } + } + + // build triangle strips / fans + BuildGlCmds (); +} + +//=============================================================== + +char *FindFrameFile (char *frame) +{ + int time1; + char file1[1024]; + static char retname[1024]; + char base[32]; + char suffix[32]; + 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.%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 ; i<model.num_xyz ; i++) + { + vnorms[i].numnormals = 0; + VectorClear (vnorms[i].normalsum); + } + ClearBounds (fr->mins, 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 ; i<num_tris ; i++) + { + vec3_t vtemp1, vtemp2, normal; + float ftemp; + + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + VectorNormalize (normal, normal); + + // rotate the normal so the model faces down the positive x axis + ftemp = normal[0]; + normal[0] = -normal[1]; + normal[1] = ftemp; + + for (j=0 ; j<3 ; j++) + { + index_xyz = triangles[i].index_xyz[j]; + + // rotate the vertices so the model faces down the positive x axis + // also adjust the vertices to the desired origin + ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + + adjust[0]; + ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + + adjust[1]; + ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + + adjust[2]; + + AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<model.num_xyz ; i++) + { + int j; + vec3_t v; + float maxdot; + int maxdotindex; + int c; + + c = vnorms[i].numnormals; + if (!c) + Error ("Vertex with no triangles attached"); + + VectorScale (vnorms[i].normalsum, 1.0/c, v); + VectorNormalize (v, v); + + maxdot = -999999.0; + maxdotindex = -1; + + for (j=0 ; j<NUMVERTEXNORMALS ; j++) + { + float dot; + + dot = DotProduct (v, avertexnormals[j]); + if (dot > 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<model.skinheight ; y++) + { + memcpy (cropped+y*model.skinwidth, + pixels+y*width, model.skinwidth); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, model.skinwidth, + model.skinheight, palette); + + free (pixels); + free (palette); + free (cropped); +} + + +/* +================= +Cmd_Origin +================= +*/ +void Cmd_Origin (void) +{ + // rotate points into frame of reference so model points down the + // positive x axis + GetToken (false); + adjust[1] = -atof (token); + + GetToken (false); + adjust[0] = atof (token); + + GetToken (false); + adjust[2] = -atof (token); +} + + +/* +================= +Cmd_ScaleUp +================= +*/ +void Cmd_ScaleUp (void) +{ + GetToken (false); + scale_up = atof (token); + if (g_skipmodel || g_release || g_archive) + return; + + printf ("Scale up: %f\n", scale_up); +} + + +/* +================= +Cmd_Skinsize + +Set a skin size other than the default +================= +*/ +void Cmd_Skinsize (void) +{ + GetToken (false); + g_fixedwidth = atoi(token); + GetToken (false); + g_fixedheight = atoi(token); +} + +/* +================= +Cmd_Modelname + +Gives a different name/location for the file, instead of the cddir +================= +*/ +void Cmd_Modelname (void) +{ + GetToken (false); + strcpy (modelname, token); +} + +/* +=============== +Cmd_Cd +=============== +*/ +void Cmd_Cd (void) +{ + FinishModel (); + ClearModel (); + + GetToken (false); + + // this is a silly mess... + sprintf (cdpartial, "models/%s", token); + sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); + sprintf (cddir, "%s%s", gamedir, cdpartial); + + // 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 monsters) + if (!g_only[0]) + return; + if (strncmp(token, g_only, strlen(g_only))) + { + g_skipmodel = true; + printf ("skipping %s\n", cdpartial); + } +} + diff --git a/tools/quake2/qdata/qdata.c b/tools/quake2/qdata/qdata.c index 1ba332b0..0502ec89 100644 --- a/tools/quake2/qdata/qdata.c +++ b/tools/quake2/qdata/qdata.c @@ -1,526 +1,526 @@ -#include "qdata.h" -#include "inout.h" - -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 - -char *ext_3ds = "3ds"; -char *ext_tri= "tri"; -char *trifileext; - -char game[64] = "quake2"; - -void InitPaths( int *argc, char **argv ); - -/* -======================================================= - - 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); - - 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 <sys/types.h> -#include <sys/dir.h> - -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 ; i<count ; i++) - { - ent = namelist[i]; - name = ent->d_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<numrtex ; i++) - if (!Q_strncasecmp(name, rtex[i], strlen(name))) - return; - - if (numrtex == MAX_RTEX) - Error ("numrtex == MAX_RTEX"); - - strcpy (rtex[i], name); - numrtex++; - - sprintf (path, "textures/%s.wal", name); - ReleaseFile (path); -} - -/* -=============== -Cmd_Maps - -Only relevent for release and pak files. -Releases the .bsp files for the maps, and scans all of the files to -build a list of all textures used, which are then released. -=============== -*/ -void Cmd_Maps (void) -{ - char map[1024]; - int i; - - while (TokenAvailable ()) - { - GetToken (false); - sprintf (map, "maps/%s.bsp", token); - ReleaseFile (map); - - if (!g_release) - continue; - - // get all the texture references - sprintf (map, "%smaps/%s.bsp", gamedir, token); - LoadBSPFileTexinfo (map); - for (i=0 ; i<numtexinfo ; i++) - ReleaseTexture (texinfo[i].texture); - } -} - - -//============================================================== - -/* -=============== -ParseScript -=============== -*/ -void ParseScript (void) -{ - while (1) - { - do - { // look for a line starting with a $ command - GetToken (true); - if (endofscript) - return; - if (token[0] == '$') - break; - while (TokenAvailable()) - GetToken (false); - } while (1); - - // - // model commands - // - if (!strcmp (token, "$modelname")) - Cmd_Modelname (); - else if (!strcmp (token, "$base")) - Cmd_Base (); - else if (!strcmp (token, "$cd")) - Cmd_Cd (); - else if (!strcmp (token, "$origin")) - Cmd_Origin (); - else if (!strcmp (token, "$scale")) - Cmd_ScaleUp (); - else if (!strcmp (token, "$frame")) - Cmd_Frame (); - else if (!strcmp (token, "$skin")) - Cmd_Skin (); - else if (!strcmp (token, "$skinsize")) - Cmd_Skinsize (); - // - // sprite commands - // - else if (!strcmp (token, "$spritename")) - Cmd_SpriteName (); - else if (!strcmp (token, "$load")) - Cmd_Load (); - else if (!strcmp (token, "$spriteframe")) - Cmd_SpriteFrame (); - // - // image commands - // - else if (!strcmp (token, "$grab")) - Cmd_Grab (); - else if (!strcmp (token, "$raw")) - Cmd_Raw (); - else if (!strcmp (token, "$colormap")) - Cmd_Colormap (); - else if (!strcmp (token, "$mippal")) - Cmd_Mippal (); - else if (!strcmp (token, "$mipdir")) - Cmd_Mipdir (); - else if (!strcmp (token, "$mip")) - Cmd_Mip (); - else if (!strcmp (token, "$environment")) - Cmd_Environment (); - // - // video - // - else if (!strcmp (token, "$video")) - Cmd_Video (); - // - // misc - // - else if (!strcmp (token, "$file")) - Cmd_File (); - else if (!strcmp (token, "$dir")) - Cmd_Dir (); - else if (!strcmp (token, "$maps")) - Cmd_Maps (); - else if (!strcmp (token, "$alphalight")) - Cmd_Alphalight (); - else if (!strcmp (token, "$inverse16table" )) - Cmd_Inverse16Table(); - else - Error ("bad command %s\n", token); - } -} - -//======================================================= - -/* -============== -main -============== -*/ -int main (int argc, char **argv) -{ - static int i; // VC4.2 compiler bug if auto... - char path[1024]; - - ExpandWildcards (&argc, &argv); - - InitPaths( &argc, argv ); - - for (i=1 ; i<argc ; i++) - { - if (!strcmp(argv[i], "-archive")) - { - // -archive f:/quake2/release/dump_11_30 - archive = true; - strcpy (archivedir, argv[i+1]); - printf ("Archiving source to: %s\n", archivedir); - i++; - } - else if (!strcmp(argv[i], "-release")) - { - g_release = true; - strcpy (g_releasedir, argv[i+1]); - printf ("Copy output to: %s\n", g_releasedir); - i++; - } - else if (!strcmp(argv[i], "-compress")) - { - g_compress_pak = true; - printf ("Compressing pakfile\n"); - } - else if (!strcmp(argv[i], "-pak")) - { - g_release = true; - g_pak = true; - printf ("Building pakfile: %s\n", argv[i+1]); - BeginPak (argv[i+1]); - i++; - } - else if (!strcmp(argv[i], "-only")) - { - strcpy (g_only, argv[i+1]); - printf ("Only grabbing %s\n", g_only); - i++; - } - else if (!strcmp(argv[i], "-3ds")) - { - do3ds = true; - printf ("loading .3ds files\n"); - } - else if (argv[i][0] == '-') - Error ("Unknown option \"%s\"", argv[i]); - else - break; - } - - if (i >= argc) - Error ("usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] ); - - if (do3ds) - trifileext = ext_3ds; - else - trifileext = ext_tri; - - for ( ; i<argc ; i++) - { - printf ("--------------- %s ---------------\n", argv[i]); - // load the script - strcpy (path, argv[i]); - DefaultExtension (path, ".qdt"); - SetQdirFromPath (path); - LoadScriptFile (ExpandArg(path)); - - // - // parse it - // - ParseScript (); - - // write out the last model - FinishModel (); - FinishSprite (); - } - - if (g_pak) - FinishPak (); - - return 0; -} - +#include "qdata.h" +#include "inout.h" + +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 + +char *ext_3ds = "3ds"; +char *ext_tri= "tri"; +char *trifileext; + +char game[64] = "quake2"; + +void InitPaths( int *argc, char **argv ); + +/* +======================================================= + + 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); + + 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 <sys/types.h> +#include <sys/dir.h> + +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 ; i<count ; i++) + { + ent = namelist[i]; + name = ent->d_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<numrtex ; i++) + if (!Q_strncasecmp(name, rtex[i], strlen(name))) + return; + + if (numrtex == MAX_RTEX) + Error ("numrtex == MAX_RTEX"); + + strcpy (rtex[i], name); + numrtex++; + + sprintf (path, "textures/%s.wal", name); + ReleaseFile (path); +} + +/* +=============== +Cmd_Maps + +Only relevent for release and pak files. +Releases the .bsp files for the maps, and scans all of the files to +build a list of all textures used, which are then released. +=============== +*/ +void Cmd_Maps (void) +{ + char map[1024]; + int i; + + while (TokenAvailable ()) + { + GetToken (false); + sprintf (map, "maps/%s.bsp", token); + ReleaseFile (map); + + if (!g_release) + continue; + + // get all the texture references + sprintf (map, "%smaps/%s.bsp", gamedir, token); + LoadBSPFileTexinfo (map); + for (i=0 ; i<numtexinfo ; i++) + ReleaseTexture (texinfo[i].texture); + } +} + + +//============================================================== + +/* +=============== +ParseScript +=============== +*/ +void ParseScript (void) +{ + while (1) + { + do + { // look for a line starting with a $ command + GetToken (true); + if (endofscript) + return; + if (token[0] == '$') + break; + while (TokenAvailable()) + GetToken (false); + } while (1); + + // + // model commands + // + if (!strcmp (token, "$modelname")) + Cmd_Modelname (); + else if (!strcmp (token, "$base")) + Cmd_Base (); + else if (!strcmp (token, "$cd")) + Cmd_Cd (); + else if (!strcmp (token, "$origin")) + Cmd_Origin (); + else if (!strcmp (token, "$scale")) + Cmd_ScaleUp (); + else if (!strcmp (token, "$frame")) + Cmd_Frame (); + else if (!strcmp (token, "$skin")) + Cmd_Skin (); + else if (!strcmp (token, "$skinsize")) + Cmd_Skinsize (); + // + // sprite commands + // + else if (!strcmp (token, "$spritename")) + Cmd_SpriteName (); + else if (!strcmp (token, "$load")) + Cmd_Load (); + else if (!strcmp (token, "$spriteframe")) + Cmd_SpriteFrame (); + // + // image commands + // + else if (!strcmp (token, "$grab")) + Cmd_Grab (); + else if (!strcmp (token, "$raw")) + Cmd_Raw (); + else if (!strcmp (token, "$colormap")) + Cmd_Colormap (); + else if (!strcmp (token, "$mippal")) + Cmd_Mippal (); + else if (!strcmp (token, "$mipdir")) + Cmd_Mipdir (); + else if (!strcmp (token, "$mip")) + Cmd_Mip (); + else if (!strcmp (token, "$environment")) + Cmd_Environment (); + // + // video + // + else if (!strcmp (token, "$video")) + Cmd_Video (); + // + // misc + // + else if (!strcmp (token, "$file")) + Cmd_File (); + else if (!strcmp (token, "$dir")) + Cmd_Dir (); + else if (!strcmp (token, "$maps")) + Cmd_Maps (); + else if (!strcmp (token, "$alphalight")) + Cmd_Alphalight (); + else if (!strcmp (token, "$inverse16table" )) + Cmd_Inverse16Table(); + else + Error ("bad command %s\n", token); + } +} + +//======================================================= + +/* +============== +main +============== +*/ +int main (int argc, char **argv) +{ + static int i; // VC4.2 compiler bug if auto... + char path[1024]; + + ExpandWildcards (&argc, &argv); + + InitPaths( &argc, argv ); + + for (i=1 ; i<argc ; i++) + { + if (!strcmp(argv[i], "-archive")) + { + // -archive f:/quake2/release/dump_11_30 + archive = true; + strcpy (archivedir, argv[i+1]); + printf ("Archiving source to: %s\n", archivedir); + i++; + } + else if (!strcmp(argv[i], "-release")) + { + g_release = true; + strcpy (g_releasedir, argv[i+1]); + printf ("Copy output to: %s\n", g_releasedir); + i++; + } + else if (!strcmp(argv[i], "-compress")) + { + g_compress_pak = true; + printf ("Compressing pakfile\n"); + } + else if (!strcmp(argv[i], "-pak")) + { + g_release = true; + g_pak = true; + printf ("Building pakfile: %s\n", argv[i+1]); + BeginPak (argv[i+1]); + i++; + } + else if (!strcmp(argv[i], "-only")) + { + strcpy (g_only, argv[i+1]); + printf ("Only grabbing %s\n", g_only); + i++; + } + else if (!strcmp(argv[i], "-3ds")) + { + do3ds = true; + printf ("loading .3ds files\n"); + } + else if (argv[i][0] == '-') + Error ("Unknown option \"%s\"", argv[i]); + else + break; + } + + if (i >= argc) + Error ("usage: %s [-archive <directory>] [-release <directory>] [-only <model>] [-3ds] file.qgr", argv[ 0 ] ); + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i<argc ; i++) + { + printf ("--------------- %s ---------------\n", argv[i]); + // load the script + strcpy (path, argv[i]); + DefaultExtension (path, ".qdt"); + SetQdirFromPath (path); + LoadScriptFile (ExpandArg(path)); + + // + // parse it + // + ParseScript (); + + // write out the last model + FinishModel (); + FinishSprite (); + } + + if (g_pak) + FinishPak (); + + return 0; +} + diff --git a/tools/quake2/qdata/qdata.h b/tools/quake2/qdata/qdata.h index f742bbec..2a1da9cb 100644 --- a/tools/quake2/qdata/qdata.h +++ b/tools/quake2/qdata/qdata.h @@ -1,75 +1,75 @@ -// qdata.h - - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <sys/stat.h> - -#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; +// qdata.h + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <sys/stat.h> + +#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/sprites.c b/tools/quake2/qdata/sprites.c index 0f3f2f3e..db812751 100644 --- a/tools/quake2/qdata/sprites.c +++ b/tools/quake2/qdata/sprites.c @@ -1,208 +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<sprite.numframes ; i++) - { - frames[i].width = LittleLong(frames[i].width); - frames[i].height = LittleLong(frames[i].height); - frames[i].origin_x = LittleLong(frames[i].origin_x); - frames[i].origin_y = LittleLong(frames[i].origin_y); - } - SafeWrite (spriteouthandle, frames, sizeof(frames[0])*sprite.numframes); - - fclose (spriteouthandle); - - spritename[0] = 0; // clear for a new sprite - sprite.numframes = 0; -} - - -/* -=============== -Cmd_Load -=============== -*/ -void Cmd_Load (void) -{ - char *name; - - GetToken (false); - - if (g_release) - return; - - name = ExpandPathAndArchive(token); - - // load the image - printf ("loading %s\n", name); - Load256Image (name, &byteimage, &lbmpalette, - &byteimagewidth, &byteimageheight); - RemapZero (byteimage, lbmpalette, - byteimagewidth, byteimageheight); -} - - -/* -=============== -Cmd_SpriteFrame -=============== -*/ -void Cmd_SpriteFrame (void) -{ - int y,xl,yl,xh,yh,w,h; - dsprframe_t *pframe; - int ox, oy; - byte *cropped; - char savename[1024]; - - GetToken (false); - xl = atoi (token); - GetToken (false); - yl = atoi (token); - GetToken (false); - w = atoi (token); - GetToken (false); - h = atoi (token); - - // origin offset is optional - if (TokenAvailable ()) - { - GetToken (false); - ox = atoi (token); - GetToken (false); - oy = atoi (token); - } - else - { - ox = w/2; - oy = h/2; - } - - if ((xl & 0x07) || (yl & 0x07) || (w & 0x07) || (h & 0x07)) - Error ("Sprite dimensions not multiples of 8\n"); - - if ((w > 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<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, w, h, lbmpalette); - - free (cropped); -} - - - -/* -============== -Cmd_SpriteName -============== -*/ -void Cmd_SpriteName (void) -{ - if (sprite.numframes) - FinishSprite (); - - GetToken (false); - strcpy (spritename, token); - memset (&sprite, 0, sizeof(sprite)); - memset (&frames, 0, sizeof(frames)); -} - + +#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<sprite.numframes ; i++) + { + frames[i].width = LittleLong(frames[i].width); + frames[i].height = LittleLong(frames[i].height); + frames[i].origin_x = LittleLong(frames[i].origin_x); + frames[i].origin_y = LittleLong(frames[i].origin_y); + } + SafeWrite (spriteouthandle, frames, sizeof(frames[0])*sprite.numframes); + + fclose (spriteouthandle); + + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; +} + + +/* +=============== +Cmd_Load +=============== +*/ +void Cmd_Load (void) +{ + char *name; + + GetToken (false); + + if (g_release) + return; + + name = ExpandPathAndArchive(token); + + // load the image + printf ("loading %s\n", name); + Load256Image (name, &byteimage, &lbmpalette, + &byteimagewidth, &byteimageheight); + RemapZero (byteimage, lbmpalette, + byteimagewidth, byteimageheight); +} + + +/* +=============== +Cmd_SpriteFrame +=============== +*/ +void Cmd_SpriteFrame (void) +{ + int y,xl,yl,xh,yh,w,h; + dsprframe_t *pframe; + int ox, oy; + byte *cropped; + char savename[1024]; + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (false); + h = atoi (token); + + // origin offset is optional + if (TokenAvailable ()) + { + GetToken (false); + ox = atoi (token); + GetToken (false); + oy = atoi (token); + } + else + { + ox = w/2; + oy = h/2; + } + + if ((xl & 0x07) || (yl & 0x07) || (w & 0x07) || (h & 0x07)) + Error ("Sprite dimensions not multiples of 8\n"); + + if ((w > 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<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, w, h, lbmpalette); + + free (cropped); +} + + + +/* +============== +Cmd_SpriteName +============== +*/ +void Cmd_SpriteName (void) +{ + if (sprite.numframes) + FinishSprite (); + + GetToken (false); + strcpy (spritename, token); + memset (&sprite, 0, sizeof(sprite)); + memset (&frames, 0, sizeof(frames)); +} + diff --git a/tools/quake2/qdata/tables.c b/tools/quake2/qdata/tables.c index 58f81c26..6aee6126 100644 --- a/tools/quake2/qdata/tables.c +++ b/tools/quake2/qdata/tables.c @@ -1,150 +1,150 @@ -#include "qdata.h" - -/* -============================================================================= - -ALPHALIGHT GENERATION - -Find alphamap values that best match modulated lightmap values - -This isn't used anymore, but I'm keeping it around... -============================================================================= -*/ - -unsigned short alphamap[32*32*32]; -unsigned char inverse16to8table[65536]; - -/* -static int FindNearestColor( unsigned int color ) -{ - int i; - int closest_so_far = 0; - float closest_distance_so_far = 100000000; - float d; - float r[2], g[2], b[2]; - - // incoming color is assumed to be in 0xRRGGBB format - r[0] = ( color & 31 ) << 3; - g[0] = ( ( color >> 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 ) ); -} +#include "qdata.h" + +/* +============================================================================= + +ALPHALIGHT GENERATION + +Find alphamap values that best match modulated lightmap values + +This isn't used anymore, but I'm keeping it around... +============================================================================= +*/ + +unsigned short alphamap[32*32*32]; +unsigned char inverse16to8table[65536]; + +/* +static int FindNearestColor( unsigned int color ) +{ + int i; + int closest_so_far = 0; + float closest_distance_so_far = 100000000; + float d; + float r[2], g[2], b[2]; + + // incoming color is assumed to be in 0xRRGGBB format + r[0] = ( color & 31 ) << 3; + g[0] = ( ( color >> 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 index 1ed1b96c..370f5e95 100644 --- a/tools/quake2/qdata/video.c +++ b/tools/quake2/qdata/video.c @@ -1,1238 +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<j ; i++) - { - val = ((unsigned short *)( soundtrack + wavinfo.dataofs))[i]; - samplecounts[val]++; - } - val = 0; - for (i=0 ; i<0x10000 ; i++) - if (samplecounts[i]) - val++; - - printf ("%i unique sample values\n", val); -} - -/* -================== -WriteSound -================== -*/ -void WriteSound (FILE *output, int frame) -{ - int start, end; - int count; - int empty = 0; - int i; - int sample; - int width; - - width = wavinfo.width * wavinfo.channels; - - start = frame*wavinfo.rate/14; - end = (frame+1)*wavinfo.rate/14; - count = end - start; - - for (i=0 ; i<count ; i++) - { - sample = start+i; - if (sample > 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<in.count ; i++) - { - b = in.data[i]; - code = index[b]; - *out_p++ = code; - - // shuffle b indexes to 0 - for (j=0 ; j<256 ; j++) - if (index[j] < code) - index[j]++; - index[b] = 0; - } - - out.count = out_p - out.data; - - return out; -} - - -//========================================================================== - -int bwt_size; -byte *bwt_data; - -int bwtCompare (const void *elem1, const void *elem2) -{ - int i; - int i1, i2; - int b1, b2; - - i1 = *(int *)elem1; - i2 = *(int *)elem2; - - for (i=0 ; i<bwt_size ; i++) - { - b1 = bwt_data[i1]; - b2 = bwt_data[i2]; - if (b1 < b2) - return -1; - if (b1 > 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<in.count ; i++) - sorted[i] = i; - qsort (sorted, in.count, sizeof(*sorted), bwtCompare); - - out_p = out.data = malloc(in.count + 8); - - // 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 head index - for (i=0 ; i<in.count ; i++) - if (sorted[i] == 0) - break; - *out_p++ = i&255; - *out_p++ = (i>>8)&255; - *out_p++ = (i>>16)&255; - *out_p++ = (i>>24)&255; - - // write the L column - for (i=0 ; i<in.count ; i++) - *out_p++ = in.data[(sorted[i]+in.count-1)%in.count]; - - free (sorted); - - out.count = out_p - out.data; - - return out; -} - -//========================================================================== - -typedef struct hnode_s -{ - int count; - qboolean used; - int children[2]; -} hnode_t; - -int numhnodes; -hnode_t hnodes[512]; -unsigned charbits[256]; -int charbitscount[256]; - -int SmallestNode (void) -{ - 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; -} - -void BuildChars (int nodenum, unsigned bits, int bitcount) -{ - hnode_t *node; - - if (nodenum < 256) - { - if (bitcount > 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<in.count ; i++) - hnodes[in.data[i]].count++; - - // normalize counts - max = 0; - maxchar = 0; - for (i=0 ; i<256 ; i++) - { - if (hnodes[i].count > 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<in.count ; i++) - { - c = charbitscount[in.data[i]]; - bits = charbits[in.data[i]]; - while (c) - { - c--; - if (bits & (1<<c)) - out_p[outbits>>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<in.count ; ) - { - val = in.data[i]; - rle_bytes[val]++; - repeat = 1; - i++; - while (i<in.count && repeat < 255 && in.data[i] == val) - { - repeat++; - i++; - } -if (repeat < 256) -rle_counts[repeat]++; - if (repeat > 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 ; ) - { - val = in.data[i]; -#if 1 -// chained search - bestlength = 0; - beststart = 0; - - max = FRONT_WINDOW; - if (i + max > in.count) - max = in.count - i; - - start = lzss_head[val]; - while (start != -1 && start >= i-BACK_WINDOW) - { - // count match length - for (j=0 ; j<max ; j++) - if (in.data[start+j] != in.data[i+j]) - break; - if (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<max ; j++) - if (in.data[start+j] != in.data[i+j]) - break; - if (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<<j) ) - out_p[outbits>>3] |= 1<<(outbits&7); - } - else - { // output a phrase - outbits++; // leave a 0 bit to mark phrase - for (j=0 ; j<BACK_BITS ; j++, outbits++) - if (beststart & (1<<j) ) - out_p[outbits>>3] |= 1<<(outbits&7); - for (j=0 ; j<FRONT_BITS ; j++, outbits++) - if (bestlength & (1<<j) ) - out_p[outbits>>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<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; -} - - -/* -================== -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); -} - - -/* -================== -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; -#if 1 - 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; - } -#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<HUF_TOKENS ; j++) - { - if (hnodes1[i][j].count > max) - max = hnodes1[i][j].count; - } - if (max == 0) - max = 1; - total = 0; - for (j=0 ; j<HUF_TOKENS ; j++) - { // easy to overflow 32 bits here! - 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); - } - -#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<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; -#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<<c)) - out_p[outbits>>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 <directory> <framedigits> -=============== -*/ -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); -} +#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<j ; i++) + { + val = ((unsigned short *)( soundtrack + wavinfo.dataofs))[i]; + samplecounts[val]++; + } + val = 0; + for (i=0 ; i<0x10000 ; i++) + if (samplecounts[i]) + val++; + + printf ("%i unique sample values\n", val); +} + +/* +================== +WriteSound +================== +*/ +void WriteSound (FILE *output, int frame) +{ + int start, end; + int count; + int empty = 0; + int i; + int sample; + int width; + + width = wavinfo.width * wavinfo.channels; + + start = frame*wavinfo.rate/14; + end = (frame+1)*wavinfo.rate/14; + count = end - start; + + for (i=0 ; i<count ; i++) + { + sample = start+i; + if (sample > 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<in.count ; i++) + { + b = in.data[i]; + code = index[b]; + *out_p++ = code; + + // shuffle b indexes to 0 + for (j=0 ; j<256 ; j++) + if (index[j] < code) + index[j]++; + index[b] = 0; + } + + out.count = out_p - out.data; + + return out; +} + + +//========================================================================== + +int bwt_size; +byte *bwt_data; + +int bwtCompare (const void *elem1, const void *elem2) +{ + int i; + int i1, i2; + int b1, b2; + + i1 = *(int *)elem1; + i2 = *(int *)elem2; + + for (i=0 ; i<bwt_size ; i++) + { + b1 = bwt_data[i1]; + b2 = bwt_data[i2]; + if (b1 < b2) + return -1; + if (b1 > 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<in.count ; i++) + sorted[i] = i; + qsort (sorted, in.count, sizeof(*sorted), bwtCompare); + + out_p = out.data = malloc(in.count + 8); + + // 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 head index + for (i=0 ; i<in.count ; i++) + if (sorted[i] == 0) + break; + *out_p++ = i&255; + *out_p++ = (i>>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i<in.count ; i++) + *out_p++ = in.data[(sorted[i]+in.count-1)%in.count]; + + free (sorted); + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + +typedef struct hnode_s +{ + int count; + qboolean used; + int children[2]; +} hnode_t; + +int numhnodes; +hnode_t hnodes[512]; +unsigned charbits[256]; +int charbitscount[256]; + +int SmallestNode (void) +{ + 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; +} + +void BuildChars (int nodenum, unsigned bits, int bitcount) +{ + hnode_t *node; + + if (nodenum < 256) + { + if (bitcount > 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<in.count ; i++) + hnodes[in.data[i]].count++; + + // normalize counts + max = 0; + maxchar = 0; + for (i=0 ; i<256 ; i++) + { + if (hnodes[i].count > 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<in.count ; i++) + { + c = charbitscount[in.data[i]]; + bits = charbits[in.data[i]]; + while (c) + { + c--; + if (bits & (1<<c)) + out_p[outbits>>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<in.count ; ) + { + val = in.data[i]; + rle_bytes[val]++; + repeat = 1; + i++; + while (i<in.count && repeat < 255 && in.data[i] == val) + { + repeat++; + i++; + } +if (repeat < 256) +rle_counts[repeat]++; + if (repeat > 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 ; ) + { + val = in.data[i]; +#if 1 +// chained search + bestlength = 0; + beststart = 0; + + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j<max ; j++) + if (in.data[start+j] != in.data[i+j]) + break; + if (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<max ; j++) + if (in.data[start+j] != in.data[i+j]) + break; + if (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<<j) ) + out_p[outbits>>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j<BACK_BITS ; j++, outbits++) + if (beststart & (1<<j) ) + out_p[outbits>>3] |= 1<<(outbits&7); + for (j=0 ; j<FRONT_BITS ; j++, outbits++) + if (bestlength & (1<<j) ) + out_p[outbits>>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<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; +} + + +/* +================== +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); +} + + +/* +================== +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; +#if 1 + 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; + } +#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<HUF_TOKENS ; j++) + { + if (hnodes1[i][j].count > max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; + for (j=0 ; j<HUF_TOKENS ; j++) + { // easy to overflow 32 bits here! + 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); + } + +#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<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; +#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<<c)) + out_p[outbits>>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 <directory> <framedigits> +=============== +*/ +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 index e4e8b5dc..3698da9a 100644 --- a/tools/quake2/qdata_heretic2/adpcm.h +++ b/tools/quake2/qdata_heretic2/adpcm.h @@ -1,49 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 7e0c96d1..c32b7bf6 100644 --- a/tools/quake2/qdata_heretic2/animcomp.c +++ b/tools/quake2/qdata_heretic2/animcomp.c @@ -1,351 +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 <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <memory.h> -#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;k<MatWidth;k++) - base[k]=0.0f; - for (j=0;j<nFrames;j++) - for (k=0;k<MatWidth;k++) - base[k]+=frames[j*MatWidth+k]; - tmp=1.0f/(float)nFrames; - for (k=0;k<MatWidth;k++) - base[k]*=tmp; - for (j=0;j<nFrames;j++) - for (k=0;k<MatWidth;k++) - frames[j*MatWidth+k]-=base[k]; - - ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressDoit"); - rescale=(float *)SafeMalloc(sizeof(float)*CFrameSize, "AnimCompressDoit"); - DOsvd(frames,best,bestcomp,rescale,nFrames,MatWidth,MatHeight); - avedev=0.0; - for (l=0;l<CFrameSize;l++) - avedev+=rescale[l]; - for (l=0;l<CFrameSize;l++) - printf("%3.1f ",100.0f*rescale[l]/avedev); - printf("\n"); - for (j=0;j<nFrames;j++) - { - for (l=0;l<CFrameSize;l++) - { - bestcomp[j*CFrameSize+l]=0.0; - for (k=0;k<MatWidth;k++) - bestcomp[j*CFrameSize+l]+=best[l*MatWidth+k]*frames[j*MatWidth+k]; - } - } - numave=0; - avedev=0.0; - maxdev=0.0; - for (j=0;j<nFrames;j++) - { - for (k=0;k<MatWidth;k++) - { - ans[k]=0.0; - for (l=0;l<CFrameSize;l++) - ans[k]+=best[l*MatWidth+k]*bestcomp[j*CFrameSize+l]; - ans[k]-=frames[j*MatWidth+k]; - tmp=(float)fabs(ans[k]); - if (tmp>maxdev) - 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;k<MatWidth;k+=3) - { - if (base[k]>scale[0]) - scale[0]=base[k]; - if (base[k]<trans[0]) - trans[0]=base[k]; - - if (base[k+1]>scale[1]) - scale[1]=base[k+1]; - if (base[k+1]<trans[1]) - trans[1]=base[k+1]; - - if (base[k+2]>scale[2]) - scale[2]=base[k+2]; - if (base[k+2]<trans[2]) - trans[2]=base[k+2]; - } - - scale[0]-=trans[0]; - scale[1]-=trans[1]; - scale[2]-=trans[2]; - scale[0]/=255.0f; - scale[1]/=255.0f; - scale[2]/=255.0f; - for (k=0;k<MatWidth;k+=3) - { - t=(base[k]-trans[0])/scale[0]; - if (t<0.0f) - t=0.0f; - if (t>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;l<MatHeight;l++) - { - mx=0.0; - for (k=0;k<MatWidth;k++) - { - if (fabs(best[l*MatWidth+k])>mx) - mx=(float)fabs(best[l*MatWidth+k]); - } - if (mx>1E-8) - { - mx/=127.0f; - coffset[l]=1E30f; - cscale[l]=-1E30f; - for (j=0;j<nFrames;j++) - { - bestcomp[j*MatHeight+l]*=mx; - if (bestcomp[j*MatHeight+l]>cscale[l]) - cscale[l]=bestcomp[j*MatHeight+l]; - if (bestcomp[j*MatHeight+l]<coffset[l]) - coffset[l]=bestcomp[j*MatHeight+l]; - } - cscale[l]-=coffset[l]; - if (cscale[l]>1E-10) - { - for (j=0;j<nFrames;j++) - { - tmp=254.0f*(bestcomp[j*MatHeight+l]-coffset[l])/cscale[l]-127.0f; - if (tmp>127.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;j<nFrames;j++) - ccomp[j*MatHeight+l]=0; - } - mx=1.0f/mx; - for (k=0;k<MatWidth;k++) - { - tmp=best[l*MatWidth+k]*mx; - if (tmp>127.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;j<nFrames;j++) - ccomp[j*MatHeight+l]=0; - for (k=0;k<MatWidth;k++) - mat[k*MatHeight+l]=0; - } - } - bmin[0]=1E30f; - bmin[1]=1E30f; - bmin[2]=1E30f; - bmax[0]=-1E30f; - bmax[1]=-1E30f; - bmax[2]=-1E30f; - numave=0; - avedev=0.0; - maxdev=0.0; - ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressToBytes"); - for (j=0;j<nFrames;j++) - { - for (k=0;k<MatWidth;k++) - { - ans[k]=0.0; - for (l=0;l<CFrameSize;l++) - ans[k]+=(float)(mat[l+k*MatHeight])*((float)(ccomp[j*CFrameSize+l])*cscale[l]+coffset[l]); - ans[k]+=(float)(cbase[k])*scale[k%3]+trans[k%3]; - tmp=(float)fabs(ans[k]-frames[j*MatWidth+k]-base[k]); - if (tmp>maxdev) - maxdev=tmp; - avedev+=tmp; - numave++; - - if (bmin[k%3]>ans[k]) - bmin[k%3]=ans[k]; - if (bmax[k%3]<ans[k]) - bmax[k%3]=ans[k]; - } - } - avedev/=(float)numave; -printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev); - free(ans); -} - -void AnimCompressGetMatrix(float *mat) -{ - int k,l; - for (k=0;k<MatWidth;k++) - for (l=0;l<MatHeight;l++) - mat[k*MatHeight+l]=best[l*MatWidth+k]; -} - -void AnimCompressGetFrames(float *mat) -{ - memcpy(mat,bestcomp,CFrameSize*nFrames*sizeof(float)); -} - -void AnimCompressGetBase(int i,float *x,float *y,float *z) -{ - *x=base[i*3]; - *y=base[i*3+1]; - *z=base[i*3+2]; -} - -void AnimCompressEnd() -{ - free(matrix); - free(best); - free(delta); - free(comp); - free(tcomp); - free(bestcomp); - free(base); - free(frames); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <memory.h> +#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;k<MatWidth;k++) + base[k]=0.0f; + for (j=0;j<nFrames;j++) + for (k=0;k<MatWidth;k++) + base[k]+=frames[j*MatWidth+k]; + tmp=1.0f/(float)nFrames; + for (k=0;k<MatWidth;k++) + base[k]*=tmp; + for (j=0;j<nFrames;j++) + for (k=0;k<MatWidth;k++) + frames[j*MatWidth+k]-=base[k]; + + ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressDoit"); + rescale=(float *)SafeMalloc(sizeof(float)*CFrameSize, "AnimCompressDoit"); + DOsvd(frames,best,bestcomp,rescale,nFrames,MatWidth,MatHeight); + avedev=0.0; + for (l=0;l<CFrameSize;l++) + avedev+=rescale[l]; + for (l=0;l<CFrameSize;l++) + printf("%3.1f ",100.0f*rescale[l]/avedev); + printf("\n"); + for (j=0;j<nFrames;j++) + { + for (l=0;l<CFrameSize;l++) + { + bestcomp[j*CFrameSize+l]=0.0; + for (k=0;k<MatWidth;k++) + bestcomp[j*CFrameSize+l]+=best[l*MatWidth+k]*frames[j*MatWidth+k]; + } + } + numave=0; + avedev=0.0; + maxdev=0.0; + for (j=0;j<nFrames;j++) + { + for (k=0;k<MatWidth;k++) + { + ans[k]=0.0; + for (l=0;l<CFrameSize;l++) + ans[k]+=best[l*MatWidth+k]*bestcomp[j*CFrameSize+l]; + ans[k]-=frames[j*MatWidth+k]; + tmp=(float)fabs(ans[k]); + if (tmp>maxdev) + 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;k<MatWidth;k+=3) + { + if (base[k]>scale[0]) + scale[0]=base[k]; + if (base[k]<trans[0]) + trans[0]=base[k]; + + if (base[k+1]>scale[1]) + scale[1]=base[k+1]; + if (base[k+1]<trans[1]) + trans[1]=base[k+1]; + + if (base[k+2]>scale[2]) + scale[2]=base[k+2]; + if (base[k+2]<trans[2]) + trans[2]=base[k+2]; + } + + scale[0]-=trans[0]; + scale[1]-=trans[1]; + scale[2]-=trans[2]; + scale[0]/=255.0f; + scale[1]/=255.0f; + scale[2]/=255.0f; + for (k=0;k<MatWidth;k+=3) + { + t=(base[k]-trans[0])/scale[0]; + if (t<0.0f) + t=0.0f; + if (t>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;l<MatHeight;l++) + { + mx=0.0; + for (k=0;k<MatWidth;k++) + { + if (fabs(best[l*MatWidth+k])>mx) + mx=(float)fabs(best[l*MatWidth+k]); + } + if (mx>1E-8) + { + mx/=127.0f; + coffset[l]=1E30f; + cscale[l]=-1E30f; + for (j=0;j<nFrames;j++) + { + bestcomp[j*MatHeight+l]*=mx; + if (bestcomp[j*MatHeight+l]>cscale[l]) + cscale[l]=bestcomp[j*MatHeight+l]; + if (bestcomp[j*MatHeight+l]<coffset[l]) + coffset[l]=bestcomp[j*MatHeight+l]; + } + cscale[l]-=coffset[l]; + if (cscale[l]>1E-10) + { + for (j=0;j<nFrames;j++) + { + tmp=254.0f*(bestcomp[j*MatHeight+l]-coffset[l])/cscale[l]-127.0f; + if (tmp>127.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;j<nFrames;j++) + ccomp[j*MatHeight+l]=0; + } + mx=1.0f/mx; + for (k=0;k<MatWidth;k++) + { + tmp=best[l*MatWidth+k]*mx; + if (tmp>127.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;j<nFrames;j++) + ccomp[j*MatHeight+l]=0; + for (k=0;k<MatWidth;k++) + mat[k*MatHeight+l]=0; + } + } + bmin[0]=1E30f; + bmin[1]=1E30f; + bmin[2]=1E30f; + bmax[0]=-1E30f; + bmax[1]=-1E30f; + bmax[2]=-1E30f; + numave=0; + avedev=0.0; + maxdev=0.0; + ans=(float *)SafeMalloc(sizeof(float)*MatWidth, "AnimCompressToBytes"); + for (j=0;j<nFrames;j++) + { + for (k=0;k<MatWidth;k++) + { + ans[k]=0.0; + for (l=0;l<CFrameSize;l++) + ans[k]+=(float)(mat[l+k*MatHeight])*((float)(ccomp[j*CFrameSize+l])*cscale[l]+coffset[l]); + ans[k]+=(float)(cbase[k])*scale[k%3]+trans[k%3]; + tmp=(float)fabs(ans[k]-frames[j*MatWidth+k]-base[k]); + if (tmp>maxdev) + maxdev=tmp; + avedev+=tmp; + numave++; + + if (bmin[k%3]>ans[k]) + bmin[k%3]=ans[k]; + if (bmax[k%3]<ans[k]) + bmax[k%3]=ans[k]; + } + } + avedev/=(float)numave; +printf("%f Max Deviation (inches) %f Ave Dev. (inches)\n",maxdev,avedev); + free(ans); +} + +void AnimCompressGetMatrix(float *mat) +{ + int k,l; + for (k=0;k<MatWidth;k++) + for (l=0;l<MatHeight;l++) + mat[k*MatHeight+l]=best[l*MatWidth+k]; +} + +void AnimCompressGetFrames(float *mat) +{ + memcpy(mat,bestcomp,CFrameSize*nFrames*sizeof(float)); +} + +void AnimCompressGetBase(int i,float *x,float *y,float *z) +{ + *x=base[i*3]; + *y=base[i*3+1]; + *z=base[i*3+2]; +} + +void AnimCompressEnd() +{ + free(matrix); + free(best); + free(delta); + free(comp); + free(tcomp); + free(bestcomp); + free(base); + free(frames); +} diff --git a/tools/quake2/qdata_heretic2/animcomp.h b/tools/quake2/qdata_heretic2/animcomp.h index 7378b502..15d0dc5b 100644 --- a/tools/quake2/qdata_heretic2/animcomp.h +++ b/tools/quake2/qdata_heretic2/animcomp.h @@ -1,43 +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 -*/ - -#if !defined(ANIMCOMP_INC) -#define ANIMCOMP_INC - -#ifdef __cplusplus -extern "C" -{ -#endif -void AnimCompressInit(int nFrames,int nVerts,int CompressedFrameSize); -void AnimSetFrame(int frame,int index,float x,float y,float z); -void AnimCompressDoit(); -void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax); -void AnimCompressGetMatrix(float *mat); -void AnimCompressGetFrames(float *mat); -void AnimCompressGetBase(int i,float *x,float *y,float *z); -void AnimCompressEnd(); -void DOsvdPlane(float *pnts,int npnts,float *n,float *base); -#ifdef __cplusplus -} -#endif - -#endif - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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(ANIMCOMP_INC) +#define ANIMCOMP_INC + +#ifdef __cplusplus +extern "C" +{ +#endif +void AnimCompressInit(int nFrames,int nVerts,int CompressedFrameSize); +void AnimSetFrame(int frame,int index,float x,float y,float z); +void AnimCompressDoit(); +void AnimCompressToBytes(float *trans,float *scale,char *mat,char *ccomp,unsigned char *cbase,float *cscale,float *coffset,float *bmin,float *bmax); +void AnimCompressGetMatrix(float *mat); +void AnimCompressGetFrames(float *mat); +void AnimCompressGetBase(int i,float *x,float *y,float *z); +void AnimCompressEnd(); +void DOsvdPlane(float *pnts,int npnts,float *n,float *base); +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/tools/quake2/qdata_heretic2/anorms.h b/tools/quake2/qdata_heretic2/anorms.h index f66b084a..f240902b 100644 --- a/tools/quake2/qdata_heretic2/anorms.h +++ b/tools/quake2/qdata_heretic2/anorms.h @@ -1,183 +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 -*/ - - {-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}, +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + {-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}, \ No newline at end of file diff --git a/tools/quake2/qdata_heretic2/book.c b/tools/quake2/qdata_heretic2/book.c index a65174a6..fd8072cb 100644 --- a/tools/quake2/qdata_heretic2/book.c +++ b/tools/quake2/qdata_heretic2/book.c @@ -1,372 +1,372 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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" - -byte *byteimage, *lbmpalette; -int byteimagewidth, byteimageheight; - -qboolean TrueColorImage; -int longimagewidth, longimageheight; - -char book_prefix[1024]; -byte buffer[640 * 480]; -unsigned long bufferl[640 * 480]; - -miptex_t *CreateBook8(byte *buffer, int w, int h, byte *palette, int *FinalSize) -{ - miptex_t *mp; - int i, j; - byte *pos; - int size; - - size = sizeof(*mp) + (w * h); - mp = (miptex_t *)SafeMalloc(size, "CreateBook8"); - memset(mp, 0, size); - - mp->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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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" + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +qboolean TrueColorImage; +int longimagewidth, longimageheight; + +char book_prefix[1024]; +byte buffer[640 * 480]; +unsigned long bufferl[640 * 480]; + +miptex_t *CreateBook8(byte *buffer, int w, int h, byte *palette, int *FinalSize) +{ + miptex_t *mp; + int i, j; + byte *pos; + int size; + + size = sizeof(*mp) + (w * h); + mp = (miptex_t *)SafeMalloc(size, "CreateBook8"); + memset(mp, 0, size); + + mp->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 index db7c0add..d029a335 100644 --- a/tools/quake2/qdata_heretic2/common/bspfile.c +++ b/tools/quake2/qdata_heretic2/common/bspfile.c @@ -1,793 +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<visrow ; j++) - { - *dest_p++ = vis[j]; - if (vis[j]) - continue; - - rep = 1; - for ( j++; j<visrow ; j++) - if (vis[j] || rep == 255) - break; - else - rep++; - *dest_p++ = rep; - j--; - } - - return dest_p - dest; -} - - -/* -=================== -DecompressVis -=================== -*/ -void DecompressVis (byte *in, byte *decompressed) -{ - int c; - byte *out; - int row; - -// row = (r_numvisleafs+7)>>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 ; i<nummodels ; i++) - { - d = &dmodels[i]; - - d->firstface = 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 ; i<numvertexes ; i++) - { - for (j=0 ; j<3 ; j++) - dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]); - } - -// -// planes -// - for (i=0 ; i<numplanes ; i++) - { - for (j=0 ; j<3 ; j++) - dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]); - dplanes[i].dist = LittleFloat (dplanes[i].dist); - dplanes[i].type = LittleLong (dplanes[i].type); - } - -// -// texinfos -// - for (i=0 ; i<numtexinfo ; i++) - { - for (j=0 ; j<8 ; j++) - texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]); - texinfo[i].flags = LittleLong (texinfo[i].flags); - texinfo[i].value = LittleLong (texinfo[i].value); - texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo); - } - -// -// faces -// - for (i=0 ; i<numfaces ; i++) - { - dfaces[i].texinfo = LittleShort (dfaces[i].texinfo); - dfaces[i].planenum = LittleShort (dfaces[i].planenum); - dfaces[i].side = LittleShort (dfaces[i].side); - dfaces[i].lighting.c = LittleLong (dfaces[i].lighting.c); - dfaces[i].lightofs = LittleLong (dfaces[i].lightofs); - dfaces[i].firstedge = LittleLong (dfaces[i].firstedge); - dfaces[i].numedges = LittleShort (dfaces[i].numedges); - } - -// -// nodes -// - for (i=0 ; i<numnodes ; i++) - { - dnodes[i].planenum = LittleLong (dnodes[i].planenum); - for (j=0 ; j<3 ; j++) - { - dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]); - dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]); - } - dnodes[i].children[0] = LittleLong (dnodes[i].children[0]); - dnodes[i].children[1] = LittleLong (dnodes[i].children[1]); - dnodes[i].firstface = LittleShort (dnodes[i].firstface); - dnodes[i].numfaces = LittleShort (dnodes[i].numfaces); - } - -// -// leafs -// - for (i=0 ; i<numleafs ; i++) - { - dleafs[i].contents = LittleLong (dleafs[i].contents); - dleafs[i].cluster = LittleShort (dleafs[i].cluster); - dleafs[i].area = LittleShort (dleafs[i].area); - for (j=0 ; j<3 ; j++) - { - dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]); - dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]); - } - - dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface); - dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces); - dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush); - dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes); - } - -// -// leaffaces -// - for (i=0 ; i<numleaffaces ; i++) - dleaffaces[i] = LittleShort (dleaffaces[i]); - -// -// leafbrushes -// - for (i=0 ; i<numleafbrushes ; i++) - dleafbrushes[i] = LittleShort (dleafbrushes[i]); - -// -// surfedges -// - for (i=0 ; i<numsurfedges ; i++) - dsurfedges[i] = LittleLong (dsurfedges[i]); - -// -// edges -// - for (i=0 ; i<numedges ; i++) - { - dedges[i].v[0] = LittleShort (dedges[i].v[0]); - dedges[i].v[1] = LittleShort (dedges[i].v[1]); - } - -// -// brushes -// - for (i=0 ; i<numbrushes ; i++) - { - dbrushes[i].firstside = LittleLong (dbrushes[i].firstside); - dbrushes[i].numsides = LittleLong (dbrushes[i].numsides); - dbrushes[i].contents = LittleLong (dbrushes[i].contents); - } - -// -// areas -// - for (i=0 ; i<numareas ; i++) - { - dareas[i].numareaportals = LittleLong (dareas[i].numareaportals); - dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal); - } - -// -// areasportals -// - for (i=0 ; i<numareaportals ; i++) - { - dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum); - dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea); - } - -// -// brushsides -// - for (i=0 ; i<numbrushsides ; i++) - { - dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum); - dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo); - } - -// -// visibility -// - if (todisk) - j = dvis->numclusters; - else - j = LittleLong(dvis->numclusters); - dvis->numclusters = LittleLong (dvis->numclusters); - for (i=0 ; i<j ; i++) - { - dvis->bitofs[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 ; i<num_entities ; i++) - { - ep = entities[i].epairs; - if (!ep) - continue; // ent got removed - - strcat (end,"{\n"); - end += 2; - - for (ep = entities[i].epairs ; ep ; ep=ep->next) - { - 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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<visrow ; j++) + { + *dest_p++ = vis[j]; + if (vis[j]) + continue; + + rep = 1; + for ( j++; j<visrow ; j++) + if (vis[j] || rep == 255) + break; + else + rep++; + *dest_p++ = rep; + j--; + } + + return dest_p - dest; +} + + +/* +=================== +DecompressVis +=================== +*/ +void DecompressVis (byte *in, byte *decompressed) +{ + int c; + byte *out; + int row; + +// row = (r_numvisleafs+7)>>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 ; i<nummodels ; i++) + { + d = &dmodels[i]; + + d->firstface = 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 ; i<numvertexes ; i++) + { + for (j=0 ; j<3 ; j++) + dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]); + } + +// +// planes +// + for (i=0 ; i<numplanes ; i++) + { + for (j=0 ; j<3 ; j++) + dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]); + dplanes[i].dist = LittleFloat (dplanes[i].dist); + dplanes[i].type = LittleLong (dplanes[i].type); + } + +// +// texinfos +// + for (i=0 ; i<numtexinfo ; i++) + { + for (j=0 ; j<8 ; j++) + texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]); + texinfo[i].flags = LittleLong (texinfo[i].flags); + texinfo[i].value = LittleLong (texinfo[i].value); + texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo); + } + +// +// faces +// + for (i=0 ; i<numfaces ; i++) + { + dfaces[i].texinfo = LittleShort (dfaces[i].texinfo); + dfaces[i].planenum = LittleShort (dfaces[i].planenum); + dfaces[i].side = LittleShort (dfaces[i].side); + dfaces[i].lighting.c = LittleLong (dfaces[i].lighting.c); + dfaces[i].lightofs = LittleLong (dfaces[i].lightofs); + dfaces[i].firstedge = LittleLong (dfaces[i].firstedge); + dfaces[i].numedges = LittleShort (dfaces[i].numedges); + } + +// +// nodes +// + for (i=0 ; i<numnodes ; i++) + { + dnodes[i].planenum = LittleLong (dnodes[i].planenum); + for (j=0 ; j<3 ; j++) + { + dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]); + dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]); + } + dnodes[i].children[0] = LittleLong (dnodes[i].children[0]); + dnodes[i].children[1] = LittleLong (dnodes[i].children[1]); + dnodes[i].firstface = LittleShort (dnodes[i].firstface); + dnodes[i].numfaces = LittleShort (dnodes[i].numfaces); + } + +// +// leafs +// + for (i=0 ; i<numleafs ; i++) + { + dleafs[i].contents = LittleLong (dleafs[i].contents); + dleafs[i].cluster = LittleShort (dleafs[i].cluster); + dleafs[i].area = LittleShort (dleafs[i].area); + for (j=0 ; j<3 ; j++) + { + dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]); + dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]); + } + + dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface); + dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces); + dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush); + dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes); + } + +// +// leaffaces +// + for (i=0 ; i<numleaffaces ; i++) + dleaffaces[i] = LittleShort (dleaffaces[i]); + +// +// leafbrushes +// + for (i=0 ; i<numleafbrushes ; i++) + dleafbrushes[i] = LittleShort (dleafbrushes[i]); + +// +// surfedges +// + for (i=0 ; i<numsurfedges ; i++) + dsurfedges[i] = LittleLong (dsurfedges[i]); + +// +// edges +// + for (i=0 ; i<numedges ; i++) + { + dedges[i].v[0] = LittleShort (dedges[i].v[0]); + dedges[i].v[1] = LittleShort (dedges[i].v[1]); + } + +// +// brushes +// + for (i=0 ; i<numbrushes ; i++) + { + dbrushes[i].firstside = LittleLong (dbrushes[i].firstside); + dbrushes[i].numsides = LittleLong (dbrushes[i].numsides); + dbrushes[i].contents = LittleLong (dbrushes[i].contents); + } + +// +// areas +// + for (i=0 ; i<numareas ; i++) + { + dareas[i].numareaportals = LittleLong (dareas[i].numareaportals); + dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal); + } + +// +// areasportals +// + for (i=0 ; i<numareaportals ; i++) + { + dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum); + dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea); + } + +// +// brushsides +// + for (i=0 ; i<numbrushsides ; i++) + { + dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum); + dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo); + } + +// +// visibility +// + if (todisk) + j = dvis->numclusters; + else + j = LittleLong(dvis->numclusters); + dvis->numclusters = LittleLong (dvis->numclusters); + for (i=0 ; i<j ; i++) + { + dvis->bitofs[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 ; i<num_entities ; i++) + { + ep = entities[i].epairs; + if (!ep) + continue; // ent got removed + + strcat (end,"{\n"); + end += 2; + + for (ep = entities[i].epairs ; ep ; ep=ep->next) + { + 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 index c08cf6c9..4e5453bb 100644 --- a/tools/quake2/qdata_heretic2/common/bspfile.h +++ b/tools/quake2/qdata_heretic2/common/bspfile.h @@ -1,133 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 1eeb3c49..c5f5c3a6 100644 --- a/tools/quake2/qdata_heretic2/common/cmdlib.c +++ b/tools/quake2/qdata_heretic2/common/cmdlib.c @@ -1,1238 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#endif - -#if defined (__linux__) || defined (__APPLE__) -#include <unistd.h> -#endif - -#ifdef NeXT -#include <libc.h> -#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; i<strlen(conv_str); i++) - conv_str[i]=tolower(conv_str[i]); -} -#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 = 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<myargc;i++) - { - if ( !Q_stricmp(check, myargv[i]) ) - return i; - } - - return 0; -} - - - -/* -================ -Q_filelength -================ -*/ -int Q_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; -} - - -FILE *SafeOpenWrite (const char *filename) -{ - FILE *f; - - f = fopen(filename, "wb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - -FILE *SafeOpenRead (const char *filename) -{ - FILE *f; - - f = fopen(filename, "rb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - - -void SafeRead (FILE *f, void *buffer, int count) -{ - if ( fread (buffer, 1, count, f) != (size_t)count) - Error ("File read failure"); -} - - -void SafeWrite (FILE *f, const void *buffer, int count) -{ - if (fwrite (buffer, 1, count, f) != (size_t)count) - Error ("File write failure"); -} - - -/* -============== -FileExists -============== -*/ -qboolean FileExists (const char *filename) -{ - FILE *f; - - f = fopen (filename, "r"); - if (!f) - return false; - fclose (f); - return true; -} - -/* -============== -LoadFile -============== -*/ -int LoadFile( const char *filename, void **bufferptr ) -{ - FILE *f; - int length; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - buffer = safe_malloc (length+1); - ((char *)buffer)[length] = 0; - SafeRead (f, buffer, length); - fclose (f); - - *bufferptr = buffer; - return length; -} - - -/* -============== -LoadFileBlock -- -rounds up memory allocation to 4K boundry -- -============== -*/ -int LoadFileBlock( const char *filename, void **bufferptr ) -{ - FILE *f; - int length, nBlock, nAllocSize; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - nAllocSize = length; - nBlock = nAllocSize % MEM_BLOCKSIZE; - if ( nBlock > 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 -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include <unistd.h> +#endif + +#ifdef NeXT +#include <libc.h> +#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; i<strlen(conv_str); i++) + conv_str[i]=tolower(conv_str[i]); +} +#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 = 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<myargc;i++) + { + if ( !Q_stricmp(check, myargv[i]) ) + return i; + } + + return 0; +} + + + +/* +================ +Q_filelength +================ +*/ +int Q_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; +} + + +FILE *SafeOpenWrite (const char *filename) +{ + FILE *f; + + f = fopen(filename, "wb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + +FILE *SafeOpenRead (const char *filename) +{ + FILE *f; + + f = fopen(filename, "rb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + + +void SafeRead (FILE *f, void *buffer, int count) +{ + if ( fread (buffer, 1, count, f) != (size_t)count) + Error ("File read failure"); +} + + +void SafeWrite (FILE *f, const void *buffer, int count) +{ + if (fwrite (buffer, 1, count, f) != (size_t)count) + Error ("File write failure"); +} + + +/* +============== +FileExists +============== +*/ +qboolean FileExists (const char *filename) +{ + FILE *f; + + f = fopen (filename, "r"); + if (!f) + return false; + fclose (f); + return true; +} + +/* +============== +LoadFile +============== +*/ +int LoadFile( const char *filename, void **bufferptr ) +{ + FILE *f; + int length; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +LoadFileBlock +- +rounds up memory allocation to 4K boundry +- +============== +*/ +int LoadFileBlock( const char *filename, void **bufferptr ) +{ + FILE *f; + int length, nBlock, nAllocSize; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + nAllocSize = length; + nBlock = nAllocSize % MEM_BLOCKSIZE; + if ( nBlock > 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 index ba7bacde..edc29d5c 100644 --- a/tools/quake2/qdata_heretic2/common/cmdlib.h +++ b/tools/quake2/qdata_heretic2/common/cmdlib.h @@ -1,177 +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 <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <time.h> -#include <stdarg.h> - -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <stdarg.h> + +#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 index 1ef28c0f..77e7414d 100644 --- a/tools/quake2/qdata_heretic2/common/her2_threads.h +++ b/tools/quake2/qdata_heretic2/common/her2_threads.h @@ -1,35 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index ef21edea..33eac651 100644 --- a/tools/quake2/qdata_heretic2/common/inout.c +++ b/tools/quake2/qdata_heretic2/common/inout.c @@ -1,367 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); - 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 level='flag'> - message string - .. various nodes to describe corresponding geometry .. - </message> - */ - 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); + 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 level='flag'> + message string + .. various nodes to describe corresponding geometry .. + </message> + */ + 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 index 4843a7b6..05b56a09 100644 --- a/tools/quake2/qdata_heretic2/common/inout.h +++ b/tools/quake2/qdata_heretic2/common/inout.h @@ -1,63 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 686c0191..12cdd193 100644 --- a/tools/quake2/qdata_heretic2/common/l3dslib.c +++ b/tools/quake2/qdata_heretic2/common/l3dslib.c @@ -1,476 +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 <stdio.h> -#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<numtris ; i++) - { - for (j=0 ; j<3 ; j++) - { - for (k=0 ; k<3 ; k++) - { - ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; - } - } - } - - totaltris += numtris; - numtris = 0; - vertsfound = 0; - trisfound = 0; -} - - -int ParseVertexL (FILE *input) -{ - int i, j, startbytesread, numverts; - unsigned short tshort; - - if (vertsfound) - Error ("Error: Multiple vertex chunks"); - - vertsfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numverts = (int)tshort; - - if (numverts > MAXVERTS) - Error ("Error: Too many vertices"); - - for (i=0 ; i<numverts ; i++) - { - for (j=0 ; j<3 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&fverts[i][j], sizeof(float), 1, input); - bytesread += sizeof(float); - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseFaceL1 (FILE *input) -{ - - int i, j, startbytesread; - unsigned short tshort; - - if (trisfound) - Error ("Error: Multiple face chunks"); - - trisfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numtris = (int)tshort; - - if (numtris > MAXTRIANGLES) - Error ("Error: Too many triangles"); - - for (i=0 ; i<numtris ; i++) - { - for (j=0 ; j<4 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - tris[i].v[j] = (int)tshort; - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseChunk (FILE *input) -{ -#define BLOCK_SIZE 4096 - char temp[BLOCK_SIZE]; - unsigned short type; - int i, length, w, t, retval; - - level++; - retval = 0; - -// chunk type - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&type, sizeof(type), 1, input); - bytesread += sizeof(type); - -// chunk length - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&length, sizeof(length), 1, input); - bytesread += sizeof(length); - w = length - 6; - -// process chunk if we care about it, otherwise skip it - switch (type) - { - case TRI_VERTEXL: - w -= ParseVertexL (input); - goto ParseSubchunk; - - case TRI_FACEL1: - w -= ParseFaceL1 (input); - goto ParseSubchunk; - - case EDIT_OBJECT: - // read the name - i = 0; - - do - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&temp[i], 1, 1, input); - i++; - w--; - bytesread++; - } while (temp[i-1]); - - case MAIN3DS: - case OBJ_TRIMESH: - case EDIT3DS: - // parse through subchunks -ParseSubchunk: - while (w > 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); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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<numtris ; i++) + { + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; + } + } + } + + totaltris += numtris; + numtris = 0; + vertsfound = 0; + trisfound = 0; +} + + +int ParseVertexL (FILE *input) +{ + int i, j, startbytesread, numverts; + unsigned short tshort; + + if (vertsfound) + Error ("Error: Multiple vertex chunks"); + + vertsfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numverts = (int)tshort; + + if (numverts > MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i<numverts ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&fverts[i][j], sizeof(float), 1, input); + bytesread += sizeof(float); + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseFaceL1 (FILE *input) +{ + + int i, j, startbytesread; + unsigned short tshort; + + if (trisfound) + Error ("Error: Multiple face chunks"); + + trisfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numtris = (int)tshort; + + if (numtris > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i<numtris ; i++) + { + for (j=0 ; j<4 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + tris[i].v[j] = (int)tshort; + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseChunk (FILE *input) +{ +#define BLOCK_SIZE 4096 + char temp[BLOCK_SIZE]; + unsigned short type; + int i, length, w, t, retval; + + level++; + retval = 0; + +// chunk type + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&type, sizeof(type), 1, input); + bytesread += sizeof(type); + +// chunk length + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&length, sizeof(length), 1, input); + bytesread += sizeof(length); + w = length - 6; + +// process chunk if we care about it, otherwise skip it + switch (type) + { + case TRI_VERTEXL: + w -= ParseVertexL (input); + goto ParseSubchunk; + + case TRI_FACEL1: + w -= ParseFaceL1 (input); + goto ParseSubchunk; + + case EDIT_OBJECT: + // read the name + i = 0; + + do + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp[i], 1, 1, input); + i++; + w--; + bytesread++; + } while (temp[i-1]); + + case MAIN3DS: + case OBJ_TRIMESH: + case EDIT3DS: + // parse through subchunks +ParseSubchunk: + while (w > 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 index 899b9fe6..7a26ade9 100644 --- a/tools/quake2/qdata_heretic2/common/l3dslib.h +++ b/tools/quake2/qdata_heretic2/common/l3dslib.h @@ -1,28 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 7e3611ac..7c1f714f 100644 --- a/tools/quake2/qdata_heretic2/common/lbmlib.c +++ b/tools/quake2/qdata_heretic2/common/lbmlib.c @@ -1,1052 +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 (count<bpwidth); - - if (count>bpwidth) - 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) - { - if (bmhd.compression == cm_rle1) - body_p = LBMRLEDecompress ((byte *)body_p - , pic_p , bmhd.w); - else if (bmhd.compression == cm_none) - { - memcpy (pic_p,body_p,bmhd.w); - body_p += Align(bmhd.w); - } - } - - } - else - { - // - // unpack ILBM - // - Error ("%s is an interlaced LBM, not packed", filename); - } - break; - } - - LBM_P += Align(chunklength); - } - - free (LBMbuffer); - - *picture = picbuffer; - - if (palette) - *palette = cmapbuffer; -} - - -/* -============================================================================ - - WRITE LBM - -============================================================================ -*/ - -/* -============== -WriteLBMfile -============== -*/ -void WriteLBMfile (char *filename, byte *data, - int width, int height, byte *palette) -{ - byte *lbm, *lbmptr; - int *formlength, *bmhdlength, *cmaplength, *bodylength; - int length; - bmhd_t basebmhd; - - lbm = lbmptr = malloc (width*height+1000); - -// -// start FORM -// - *lbmptr++ = 'F'; - *lbmptr++ = 'O'; - *lbmptr++ = 'R'; - *lbmptr++ = 'M'; - - formlength = (int*)lbmptr; - lbmptr+=4; // leave space for length - - *lbmptr++ = 'P'; - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = ' '; - -// -// write BMHD -// - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = 'H'; - *lbmptr++ = 'D'; - - bmhdlength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memset (&basebmhd,0,sizeof(basebmhd)); - basebmhd.w = BigShort((short)width); - basebmhd.h = BigShort((short)height); - basebmhd.nPlanes = BigShort(8); - basebmhd.xAspect = BigShort(5); - basebmhd.yAspect = BigShort(6); - basebmhd.pageWidth = BigShort((short)width); - basebmhd.pageHeight = BigShort((short)height); - - memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); - lbmptr += sizeof(basebmhd); - - length = lbmptr-(byte *)bmhdlength-4; - *bmhdlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write CMAP -// - *lbmptr++ = 'C'; - *lbmptr++ = 'M'; - *lbmptr++ = 'A'; - *lbmptr++ = 'P'; - - cmaplength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,palette,768); - lbmptr += 768; - - length = lbmptr-(byte *)cmaplength-4; - *cmaplength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write BODY -// - *lbmptr++ = 'B'; - *lbmptr++ = 'O'; - *lbmptr++ = 'D'; - *lbmptr++ = 'Y'; - - bodylength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,data,width*height); - lbmptr += width*height; - - length = lbmptr-(byte *)bodylength-4; - *bodylength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// done -// - length = lbmptr-(byte *)formlength-4; - *formlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write output file -// - SaveFile (filename, lbm, lbmptr-lbm); - free (lbm); -} - - -/* -============================================================================ - -LOAD PCX - -============================================================================ -*/ - -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; - -/* -============== -LoadPCX -============== -*/ -void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) -{ - byte *raw; - pcx_t *pcx; - int x, y; - int len; - int dataByte, runLength; - byte *out, *pix; - - // - // load the file - // - len = LoadFile (filename, (void **)&raw); - - // - // parse the PCX file - // - pcx = (pcx_t *)raw; - raw = &pcx->data; - - 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<height ; i++) - { - for (j=0 ; j<width ; j++) - { - if ( (*data & 0xc0) != 0xc0) - *pack++ = *data++; - else - { - *pack++ = 0xc1; - *pack++ = *data++; - } - } - } -*/ - for (i=0 ; i<height ; i++) - { - curByte = *data; - curRepCount = 0; - for (j=0 ; j<width ; j++) - { - if (*data == curByte) - { - curRepCount++; - data++; - continue; - } - StuffPackedByte(curRepCount, curByte, &pack); - curByte = *data++; - curRepCount = 1; - } - StuffPackedByte(curRepCount, curByte, &pack); - } - // write the palette - *pack++ = 0x0c; // palette ID byte - for (i=0 ; i<768 ; i++) - *pack++ = *palette++; - -// write output file - length = pack - (byte *)pcx; - SaveFile (filename, pcx, length); - - free (pcx); -} - - -/* -============================================================================ - -LOAD IMAGE - -============================================================================ -*/ - -/* -============== -Load256Image - -Will load either an lbm or pcx, depending on extension. -Any of the return pointers can be NULL if you don't want them. -============== -*/ -void Load256Image (char *name, byte **pixels, byte **palette, - int *width, int *height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_strcasecmp (ext, "lbm")) - { - LoadLBM (name, pixels, palette); - if (width) - *width = bmhd.w; - if (height) - *height = bmhd.h; - } - else if (!Q_strcasecmp (ext, "pcx")) - { - LoadPCX (name, pixels, palette, width, height); - } - else - Error ("%s doesn't have a known image extension", name); -} - - -/* -============== -Save256Image - -Will save either an lbm or pcx, depending on extension. -============== -*/ -void Save256Image (char *name, byte *pixels, byte *palette, - int width, int height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_strcasecmp (ext, "lbm")) - { - WriteLBMfile (name, pixels, width, height, palette); - } - else if (!Q_strcasecmp (ext, "pcx")) - { - WritePCXfile (name, pixels, width, height, palette); - } - else - Error ("%s doesn't have a known image extension", name); -} - - - - -/* -============================================================================ - -TARGA IMAGE - -============================================================================ -*/ - -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; - -int fgetLittleShort (FILE *f) -{ - byte b1, b2; - - b1 = fgetc(f); - b2 = fgetc(f); - - return((short)(b1 + (b2 << 8))); -} - -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)); -} - - -/* -============= -LoadTGA -============= -*/ -void LoadTGA(char *name, byte **pixels, int *width, int *height) -{ - int columns, rows, numPixels; - byte *pixbuf; - byte *rowBuf; - int row, column; - FILE *fin; - byte *targa_rgba; - TargaHeader targa_header; - unsigned char red, green, blue, alphabyte; - unsigned char packetHeader, packetSize, j; - int flip; - int mirror; - int rowOffset; - int pixDirection; - - fin = fopen(name, "rb"); - if (!fin) - Error ("Couldn't read %s", name); - - targa_header.id_length = fgetc(fin); - targa_header.colormap_type = fgetc(fin); - targa_header.image_type = fgetc(fin); - - targa_header.colormap_index = fgetLittleShort(fin); - targa_header.colormap_length = fgetLittleShort(fin); - targa_header.colormap_size = fgetc(fin); - targa_header.x_origin = fgetLittleShort(fin); - targa_header.y_origin = fgetLittleShort(fin); - targa_header.width = fgetLittleShort(fin); - targa_header.height = fgetLittleShort(fin); - targa_header.pixel_size = fgetc(fin); - targa_header.attributes = fgetc(fin); - flip = (targa_header.attributes & 0x020) == 0; - mirror = (targa_header.attributes & 0x010) != 0; - - if ((targa_header.image_type != 2) && (targa_header.image_type != 10)) - Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n"); - - if (targa_header.colormap_type || ((targa_header.pixel_size != 32) && (targa_header.pixel_size != 24))) - Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - if(!pixels) - return; - - targa_rgba = malloc(numPixels * 4); - *pixels = targa_rgba; - - if (flip) - { - pixbuf = targa_rgba + ((rows - 1) * columns * 4); - rowOffset = -columns * 4; - } - else - { - pixbuf = targa_rgba; - rowOffset = columns * 4; - } - if (mirror) - { - pixDirection = -4; - pixbuf += ((columns - 1) * 4); - } - else - { - pixDirection = 4; - } - - if (targa_header.id_length) - fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment - - if (targa_header.image_type == 2) - { // Uncompressed, RGB images - for(row = 0; row < rows; row++) - { - rowBuf = pixbuf; - for(column = 0; column < columns; column++) - { - 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; - } - } - pixbuf += rowOffset; - } - } - else if(targa_header.image_type == 10) - { // Runlength encoded RGB images - for(row = 0; row < rows; row++) - { - rowBuf = pixbuf; - for(column = 0; column < columns; ) - { - packetHeader = getc(fin); - packetSize = 1 + (packetHeader & 0x7f); - if (packetHeader & 0x80) - { // run-length packet - switch (targa_header.pixel_size) - { - case 24: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = 255; - break; - case 32: - blue = getc(fin); - green = getc(fin); - red = getc(fin); - alphabyte = getc(fin); - break; - } - - for(j = 0; j < packetSize; j++) - { - rowBuf[0] = red; - rowBuf[1] = green; - rowBuf[2] = blue; - rowBuf[3] = alphabyte; - rowBuf += pixDirection; - column++; - if(column == columns) - { // run spans across rows - column = 0; - row++; - if (row >= 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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 (count<bpwidth); + + if (count>bpwidth) + 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) + { + if (bmhd.compression == cm_rle1) + body_p = LBMRLEDecompress ((byte *)body_p + , pic_p , bmhd.w); + else if (bmhd.compression == cm_none) + { + memcpy (pic_p,body_p,bmhd.w); + body_p += Align(bmhd.w); + } + } + + } + else + { + // + // unpack ILBM + // + Error ("%s is an interlaced LBM, not packed", filename); + } + break; + } + + LBM_P += Align(chunklength); + } + + free (LBMbuffer); + + *picture = picbuffer; + + if (palette) + *palette = cmapbuffer; +} + + +/* +============================================================================ + + WRITE LBM + +============================================================================ +*/ + +/* +============== +WriteLBMfile +============== +*/ +void WriteLBMfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + byte *lbm, *lbmptr; + int *formlength, *bmhdlength, *cmaplength, *bodylength; + int length; + bmhd_t basebmhd; + + lbm = lbmptr = malloc (width*height+1000); + +// +// start FORM +// + *lbmptr++ = 'F'; + *lbmptr++ = 'O'; + *lbmptr++ = 'R'; + *lbmptr++ = 'M'; + + formlength = (int*)lbmptr; + lbmptr+=4; // leave space for length + + *lbmptr++ = 'P'; + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = ' '; + +// +// write BMHD +// + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = 'H'; + *lbmptr++ = 'D'; + + bmhdlength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memset (&basebmhd,0,sizeof(basebmhd)); + basebmhd.w = BigShort((short)width); + basebmhd.h = BigShort((short)height); + basebmhd.nPlanes = BigShort(8); + basebmhd.xAspect = BigShort(5); + basebmhd.yAspect = BigShort(6); + basebmhd.pageWidth = BigShort((short)width); + basebmhd.pageHeight = BigShort((short)height); + + memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); + lbmptr += sizeof(basebmhd); + + length = lbmptr-(byte *)bmhdlength-4; + *bmhdlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write CMAP +// + *lbmptr++ = 'C'; + *lbmptr++ = 'M'; + *lbmptr++ = 'A'; + *lbmptr++ = 'P'; + + cmaplength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,palette,768); + lbmptr += 768; + + length = lbmptr-(byte *)cmaplength-4; + *cmaplength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write BODY +// + *lbmptr++ = 'B'; + *lbmptr++ = 'O'; + *lbmptr++ = 'D'; + *lbmptr++ = 'Y'; + + bodylength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,data,width*height); + lbmptr += width*height; + + length = lbmptr-(byte *)bodylength-4; + *bodylength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// done +// + length = lbmptr-(byte *)formlength-4; + *formlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write output file +// + SaveFile (filename, lbm, lbmptr-lbm); + free (lbm); +} + + +/* +============================================================================ + +LOAD PCX + +============================================================================ +*/ + +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; + +/* +============== +LoadPCX +============== +*/ +void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height) +{ + byte *raw; + pcx_t *pcx; + int x, y; + int len; + int dataByte, runLength; + byte *out, *pix; + + // + // load the file + // + len = LoadFile (filename, (void **)&raw); + + // + // parse the PCX file + // + pcx = (pcx_t *)raw; + raw = &pcx->data; + + 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<height ; i++) + { + for (j=0 ; j<width ; j++) + { + if ( (*data & 0xc0) != 0xc0) + *pack++ = *data++; + else + { + *pack++ = 0xc1; + *pack++ = *data++; + } + } + } +*/ + for (i=0 ; i<height ; i++) + { + curByte = *data; + curRepCount = 0; + for (j=0 ; j<width ; j++) + { + if (*data == curByte) + { + curRepCount++; + data++; + continue; + } + StuffPackedByte(curRepCount, curByte, &pack); + curByte = *data++; + curRepCount = 1; + } + StuffPackedByte(curRepCount, curByte, &pack); + } + // write the palette + *pack++ = 0x0c; // palette ID byte + for (i=0 ; i<768 ; i++) + *pack++ = *palette++; + +// write output file + length = pack - (byte *)pcx; + SaveFile (filename, pcx, length); + + free (pcx); +} + + +/* +============================================================================ + +LOAD IMAGE + +============================================================================ +*/ + +/* +============== +Load256Image + +Will load either an lbm or pcx, depending on extension. +Any of the return pointers can be NULL if you don't want them. +============== +*/ +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_strcasecmp (ext, "lbm")) + { + LoadLBM (name, pixels, palette); + if (width) + *width = bmhd.w; + if (height) + *height = bmhd.h; + } + else if (!Q_strcasecmp (ext, "pcx")) + { + LoadPCX (name, pixels, palette, width, height); + } + else + Error ("%s doesn't have a known image extension", name); +} + + +/* +============== +Save256Image + +Will save either an lbm or pcx, depending on extension. +============== +*/ +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_strcasecmp (ext, "lbm")) + { + WriteLBMfile (name, pixels, width, height, palette); + } + else if (!Q_strcasecmp (ext, "pcx")) + { + WritePCXfile (name, pixels, width, height, palette); + } + else + Error ("%s doesn't have a known image extension", name); +} + + + + +/* +============================================================================ + +TARGA IMAGE + +============================================================================ +*/ + +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; + +int fgetLittleShort (FILE *f) +{ + byte b1, b2; + + b1 = fgetc(f); + b2 = fgetc(f); + + return((short)(b1 + (b2 << 8))); +} + +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)); +} + + +/* +============= +LoadTGA +============= +*/ +void LoadTGA(char *name, byte **pixels, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + byte *rowBuf; + int row, column; + FILE *fin; + byte *targa_rgba; + TargaHeader targa_header; + unsigned char red, green, blue, alphabyte; + unsigned char packetHeader, packetSize, j; + int flip; + int mirror; + int rowOffset; + int pixDirection; + + fin = fopen(name, "rb"); + if (!fin) + Error ("Couldn't read %s", name); + + targa_header.id_length = fgetc(fin); + targa_header.colormap_type = fgetc(fin); + targa_header.image_type = fgetc(fin); + + targa_header.colormap_index = fgetLittleShort(fin); + targa_header.colormap_length = fgetLittleShort(fin); + targa_header.colormap_size = fgetc(fin); + targa_header.x_origin = fgetLittleShort(fin); + targa_header.y_origin = fgetLittleShort(fin); + targa_header.width = fgetLittleShort(fin); + targa_header.height = fgetLittleShort(fin); + targa_header.pixel_size = fgetc(fin); + targa_header.attributes = fgetc(fin); + flip = (targa_header.attributes & 0x020) == 0; + mirror = (targa_header.attributes & 0x010) != 0; + + if ((targa_header.image_type != 2) && (targa_header.image_type != 10)) + Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n"); + + if (targa_header.colormap_type || ((targa_header.pixel_size != 32) && (targa_header.pixel_size != 24))) + Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + if(!pixels) + return; + + targa_rgba = malloc(numPixels * 4); + *pixels = targa_rgba; + + if (flip) + { + pixbuf = targa_rgba + ((rows - 1) * columns * 4); + rowOffset = -columns * 4; + } + else + { + pixbuf = targa_rgba; + rowOffset = columns * 4; + } + if (mirror) + { + pixDirection = -4; + pixbuf += ((columns - 1) * 4); + } + else + { + pixDirection = 4; + } + + if (targa_header.id_length) + fseek(fin, targa_header.id_length, SEEK_CUR); // skip TARGA image comment + + if (targa_header.image_type == 2) + { // Uncompressed, RGB images + for(row = 0; row < rows; row++) + { + rowBuf = pixbuf; + for(column = 0; column < columns; column++) + { + 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; + } + } + pixbuf += rowOffset; + } + } + else if(targa_header.image_type == 10) + { // Runlength encoded RGB images + for(row = 0; row < rows; row++) + { + rowBuf = pixbuf; + for(column = 0; column < columns; ) + { + packetHeader = getc(fin); + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) + { // run-length packet + switch (targa_header.pixel_size) + { + case 24: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = 255; + break; + case 32: + blue = getc(fin); + green = getc(fin); + red = getc(fin); + alphabyte = getc(fin); + break; + } + + for(j = 0; j < packetSize; j++) + { + rowBuf[0] = red; + rowBuf[1] = green; + rowBuf[2] = blue; + rowBuf[3] = alphabyte; + rowBuf += pixDirection; + column++; + if(column == columns) + { // run spans across rows + column = 0; + row++; + if (row >= 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 index ec0e8e2a..e050efa6 100644 --- a/tools/quake2/qdata_heretic2/common/lbmlib.h +++ b/tools/quake2/qdata_heretic2/common/lbmlib.h @@ -1,41 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 0fd9ac23..a1c0733c 100644 --- a/tools/quake2/qdata_heretic2/common/mathlib.c +++ b/tools/quake2/qdata_heretic2/common/mathlib.c @@ -1,176 +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; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index b4cbf05f..03e5325b 100644 --- a/tools/quake2/qdata_heretic2/common/mathlib.h +++ b/tools/quake2/qdata_heretic2/common/mathlib.h @@ -1,76 +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 <math.h> -/* -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <math.h> +/* +#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/path_init.c b/tools/quake2/qdata_heretic2/common/path_init.c index 0a630a10..644908ea 100644 --- a/tools/quake2/qdata_heretic2/common/path_init.c +++ b/tools/quake2/qdata_heretic2/common/path_init.c @@ -1,404 +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 <unistd.h> - #include <pwd.h> - #include <limits.h> -#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" ); -} - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <unistd.h> + #include <pwd.h> + #include <limits.h> +#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 index 34dfc2ef..b4b69ac1 100644 --- a/tools/quake2/qdata_heretic2/common/polylib.c +++ b/tools/quake2/qdata_heretic2/common/polylib.c @@ -1,656 +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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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 index e19fb2bd..68660e27 100644 --- a/tools/quake2/qdata_heretic2/common/polylib.h +++ b/tools/quake2/qdata_heretic2/common/polylib.h @@ -1,55 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 58fcda00..7e9414f3 100644 --- a/tools/quake2/qdata_heretic2/common/qfiles.c +++ b/tools/quake2/qdata_heretic2/common/qfiles.c @@ -1,82 +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 <windows.h> - -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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> + +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 index 1af6d078..1aa61983 100644 --- a/tools/quake2/qdata_heretic2/common/qfiles.h +++ b/tools/quake2/qdata_heretic2/common/qfiles.h @@ -1,619 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 25fc66d1..15042d5d 100644 --- a/tools/quake2/qdata_heretic2/common/scriplib.c +++ b/tools/quake2/qdata_heretic2/common/scriplib.c @@ -1,297 +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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index bee8d0aa..80ece66f 100644 --- a/tools/quake2/qdata_heretic2/common/scriplib.h +++ b/tools/quake2/qdata_heretic2/common/scriplib.h @@ -1,44 +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); - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 2a2b9787..ce51fb32 100644 --- a/tools/quake2/qdata_heretic2/common/threads.c +++ b/tools/quake2/qdata_heretic2/common/threads.c @@ -1,620 +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 <pthread.h> -#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 <windows.h> - -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<numthreads ; i++) - { - threadhandle[i] = CreateThread( - NULL, // LPSECURITY_ATTRIBUTES lpsa, - //0, // DWORD cbStack, - - /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ - (4096 * 1024), - - (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, - (LPVOID)i, // LPVOID lpvThreadParm, - 0, // DWORD fdwCreate, - &threadid[i]); - } - - for (i=0 ; i<numthreads ; i++) - WaitForSingleObject (threadhandle[i], INFINITE); - } - DeleteCriticalSection (&crit); - - threaded = false; - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -OSF1 - -=================================================================== -*/ - -#ifdef __osf__ -#define USED - -int numthreads = 4; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - numthreads = 4; - } -} - - -#include <pthread.h> - -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<numthreads ; i++) - { - if (pthread_create(&work_threads[i], attrib - , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) - Error ("pthread_create failed"); - } - - for (i=0 ; i<numthreads ; i++) - { - if (pthread_join (work_threads[i], &status) == -1) - Error ("pthread_join failed"); - } - - threaded = false; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -IRIX - -=================================================================== -*/ - -#ifdef _MIPS_ISA -#define USED - -#include <task.h> -#include <abi_mutex.h> -#include <sys/types.h> -#include <sys/prctl.h> - - -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<numthreads-1 ; i++) - { - pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i - , NULL, 0x200000); // 2 meg stacks - if (pid[i] == -1) - { - perror ("sproc"); - Error ("sproc failed"); - } - } - - func(i); - - for (i=0 ; i<numthreads-1 ; i++) - wait (NULL); - - threaded = false; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - - -/* -======================================================================= - - Linux pthreads - -======================================================================= -*/ - -#ifdef __linux__ -#define USED - -int numthreads = 4; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - /* default to one thread, only multi-thread when specifically told to */ - numthreads = 1; - } - if(numthreads > 1) - Sys_Printf("threads: %d\n", numthreads); -} - -#include <pthread.h> - -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<numthreads ; i++) - { - /* Default pthread attributes: joinable & non-realtime scheduling */ - if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) - Error("pthread_create failed"); - } - for (i=0 ; i<numthreads ; i++) - { - if(pthread_join(work_threads[i], (void **)&status) != 0) - Error("pthread_join failed"); - } - pthread_mutexattr_destroy(&mattrib); - threaded = false; - } - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} -#endif // ifdef __linux__ - - -/* -======================================================================= - - SINGLE THREAD - -======================================================================= -*/ - -#ifndef USED - -int numthreads = 1; - -void ThreadSetDefault (void) -{ - numthreads = 1; -} - -void ThreadLock (void) -{ -} - -void ThreadUnlock (void) -{ -} - -/* -============= -RunThreadsOn -============= -*/ -void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) -{ - int i; - int start, end; - - dispatch = 0; - workcount = workcnt; - oldf = -1; - pacifier = showpacifier; - start = I_FloatTime (); - func(0); - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <pthread.h> +#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 <windows.h> + +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<numthreads ; i++) + { + threadhandle[i] = CreateThread( + NULL, // LPSECURITY_ATTRIBUTES lpsa, + //0, // DWORD cbStack, + + /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ + (4096 * 1024), + + (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, + (LPVOID)i, // LPVOID lpvThreadParm, + 0, // DWORD fdwCreate, + &threadid[i]); + } + + for (i=0 ; i<numthreads ; i++) + WaitForSingleObject (threadhandle[i], INFINITE); + } + DeleteCriticalSection (&crit); + + threaded = false; + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +OSF1 + +=================================================================== +*/ + +#ifdef __osf__ +#define USED + +int numthreads = 4; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + numthreads = 4; + } +} + + +#include <pthread.h> + +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<numthreads ; i++) + { + if (pthread_create(&work_threads[i], attrib + , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) + Error ("pthread_create failed"); + } + + for (i=0 ; i<numthreads ; i++) + { + if (pthread_join (work_threads[i], &status) == -1) + Error ("pthread_join failed"); + } + + threaded = false; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +IRIX + +=================================================================== +*/ + +#ifdef _MIPS_ISA +#define USED + +#include <task.h> +#include <abi_mutex.h> +#include <sys/types.h> +#include <sys/prctl.h> + + +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<numthreads-1 ; i++) + { + pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i + , NULL, 0x200000); // 2 meg stacks + if (pid[i] == -1) + { + perror ("sproc"); + Error ("sproc failed"); + } + } + + func(i); + + for (i=0 ; i<numthreads-1 ; i++) + wait (NULL); + + threaded = false; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + + +/* +======================================================================= + + Linux pthreads + +======================================================================= +*/ + +#ifdef __linux__ +#define USED + +int numthreads = 4; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + /* default to one thread, only multi-thread when specifically told to */ + numthreads = 1; + } + if(numthreads > 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include <pthread.h> + +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<numthreads ; i++) + { + /* Default pthread attributes: joinable & non-realtime scheduling */ + if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) + Error("pthread_create failed"); + } + for (i=0 ; i<numthreads ; i++) + { + if(pthread_join(work_threads[i], (void **)&status) != 0) + Error("pthread_join failed"); + } + pthread_mutexattr_destroy(&mattrib); + threaded = false; + } + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} +#endif // ifdef __linux__ + + +/* +======================================================================= + + SINGLE THREAD + +======================================================================= +*/ + +#ifndef USED + +int numthreads = 1; + +void ThreadSetDefault (void) +{ + numthreads = 1; +} + +void ThreadLock (void) +{ +} + +void ThreadUnlock (void) +{ +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int start, end; + + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + start = I_FloatTime (); + func(0); + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + +#endif diff --git a/tools/quake2/qdata_heretic2/common/token.c b/tools/quake2/qdata_heretic2/common/token.c index 7fe8871f..911607cf 100644 --- a/tools/quake2/qdata_heretic2/common/token.c +++ b/tools/quake2/qdata_heretic2/common/token.c @@ -1,550 +1,550 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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.c -//** -//************************************************************************** - -// HEADER FILES ------------------------------------------------------------ - -#include "token.h" -#include "inout.h" - -// MACROS ------------------------------------------------------------------ - -// TYPES ------------------------------------------------------------------- - -typedef enum -{ - CHR_EOF, - CHR_LETTER, - CHR_NUMBER, - CHR_QUOTE, - CHR_SPECIAL -} chr_t; - -// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- - -// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- - -// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- - -static void ProcessLetterToken(void); -static void ProcessNumberToken(void); -static void ProcessQuoteToken(void); -static void ProcessSpecialToken(void); -static qboolean CheckForKeyword(void); -static void NextChr(void); - -// EXTERNAL DATA DECLARATIONS ---------------------------------------------- - -// PUBLIC DATA DEFINITIONS ------------------------------------------------- - -tokenType_t tk_Token; -int tk_Line; -int tk_IntNumber; -float tk_FloatNumber; -char *tk_String; -char tk_SourceName[MAX_FILE_NAME_LENGTH]; - -// PRIVATE DATA DEFINITIONS ------------------------------------------------ - -static char Chr; -static char *FileStart; -static char *FilePtr; -static char *FileEnd; -static qboolean SourceOpen; -static char ASCIIToChrCode[256]; -static char TokenStringBuffer[MAX_QUOTED_LENGTH]; -static qboolean IncLineNumber; -static char TempBuffer[2048]; - -static struct -{ - char *name; - tokenType_t token; -} Keywords[] = -{ - "model", TK_MODEL, - "mesh", TK_MESH, - "vertices", TK_VERTICES, - "edges", TK_EDGES, - "position", TK_POSITION, - "polygons", TK_POLYGONS, - "nodes", TK_NODES, - "rotation", TK_ROTATION, - "scaling", TK_SCALING, - "translation", TK_TRANSLATION, - "vertex", TK_VERTEX, - "HRCH", TK_HRCH, - "Softimage", TK_SOFTIMAGE, - "material", TK_MATERIAL, - "spline", TK_SPLINE, - - "Named", TK_C_NAMED, - "object", TK_OBJECT, - "Tri", TK_C_TRI, - "Vertices", TK_C_VERTICES, - "Faces", TK_C_FACES, - "Vertex", TK_C_VERTEX, - "list", TK_LIST, - "Face", TK_C_FACE, - - "Hexen", TK_C_HEXEN, - "Triangles", TK_C_TRIANGLES, - "Version", TK_C_VERSION, - "faces", TK_FACES, - "face", TK_FACE, - "origin", TK_ORIGIN, - - "DK_clusters", TK_CLUSTERS, - "DK_cluster_ncvs", TK_NUM_CLUSTER_VERTICES, - "name", TK_NAME, - "DK_cluster_name", TK_CLUSTER_NAME, - "DK_cluster_state", TK_CLUSTER_STATE, - - "actor_data", TK_ACTOR_DATA, - "uvTexture", TK_UVTEXTURE, - - NULL, -1 -}; - -static char *TokenNames[] = -{ - "<nothing>", - "<unknown_char>", - "<EOF>", - "<identifier>", - "<string>", - "<int_number>", - "<float_number>", - "(", - ")", - "{", - "}", - "[", - "]", - ":", - "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<EOF> 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; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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.c +//** +//************************************************************************** + +// HEADER FILES ------------------------------------------------------------ + +#include "token.h" +#include "inout.h" + +// MACROS ------------------------------------------------------------------ + +// TYPES ------------------------------------------------------------------- + +typedef enum +{ + CHR_EOF, + CHR_LETTER, + CHR_NUMBER, + CHR_QUOTE, + CHR_SPECIAL +} chr_t; + +// EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- + +// PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +static void ProcessLetterToken(void); +static void ProcessNumberToken(void); +static void ProcessQuoteToken(void); +static void ProcessSpecialToken(void); +static qboolean CheckForKeyword(void); +static void NextChr(void); + +// EXTERNAL DATA DECLARATIONS ---------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +tokenType_t tk_Token; +int tk_Line; +int tk_IntNumber; +float tk_FloatNumber; +char *tk_String; +char tk_SourceName[MAX_FILE_NAME_LENGTH]; + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +static char Chr; +static char *FileStart; +static char *FilePtr; +static char *FileEnd; +static qboolean SourceOpen; +static char ASCIIToChrCode[256]; +static char TokenStringBuffer[MAX_QUOTED_LENGTH]; +static qboolean IncLineNumber; +static char TempBuffer[2048]; + +static struct +{ + char *name; + tokenType_t token; +} Keywords[] = +{ + "model", TK_MODEL, + "mesh", TK_MESH, + "vertices", TK_VERTICES, + "edges", TK_EDGES, + "position", TK_POSITION, + "polygons", TK_POLYGONS, + "nodes", TK_NODES, + "rotation", TK_ROTATION, + "scaling", TK_SCALING, + "translation", TK_TRANSLATION, + "vertex", TK_VERTEX, + "HRCH", TK_HRCH, + "Softimage", TK_SOFTIMAGE, + "material", TK_MATERIAL, + "spline", TK_SPLINE, + + "Named", TK_C_NAMED, + "object", TK_OBJECT, + "Tri", TK_C_TRI, + "Vertices", TK_C_VERTICES, + "Faces", TK_C_FACES, + "Vertex", TK_C_VERTEX, + "list", TK_LIST, + "Face", TK_C_FACE, + + "Hexen", TK_C_HEXEN, + "Triangles", TK_C_TRIANGLES, + "Version", TK_C_VERSION, + "faces", TK_FACES, + "face", TK_FACE, + "origin", TK_ORIGIN, + + "DK_clusters", TK_CLUSTERS, + "DK_cluster_ncvs", TK_NUM_CLUSTER_VERTICES, + "name", TK_NAME, + "DK_cluster_name", TK_CLUSTER_NAME, + "DK_cluster_state", TK_CLUSTER_STATE, + + "actor_data", TK_ACTOR_DATA, + "uvTexture", TK_UVTEXTURE, + + NULL, -1 +}; + +static char *TokenNames[] = +{ + "<nothing>", + "<unknown_char>", + "<EOF>", + "<identifier>", + "<string>", + "<int_number>", + "<float_number>", + "(", + ")", + "{", + "}", + "[", + "]", + ":", + "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<EOF> 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 index e6aab853..ab0e0de5 100644 --- a/tools/quake2/qdata_heretic2/common/token.h +++ b/tools/quake2/qdata_heretic2/common/token.h @@ -1,132 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 4ed79051..7a0f412f 100644 --- a/tools/quake2/qdata_heretic2/common/trilib.c +++ b/tools/quake2/qdata_heretic2/common/trilib.c @@ -1,1077 +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 <stdio.h> -#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 ; i<sizeof(tf_triangle)/4 ; i++) - { - ((int *)tri)[i] = BigLong (((int *)tri)[i]); - } -} - -void LoadTRI (char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes) -{ - FILE *input; - float start; - char name[256], tex[256]; - int i, count, magic; - tf_triangle tri; - triangle_t *ptri; - int iLevel; - int exitpattern; - float t; - - if (nodesList) - { - *num_mesh_nodes = 0; - *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); - } - - 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); - - ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); - - *pptri = ptri; - - 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' ); - -// 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' ); - -// 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. */ - /* Mia culpa. */ - --iLevel; - i = -1; - do { - ++i; - fread( &(name[i]), sizeof( char ), 1, input); - } while( name[i] != '\0' ); - -// indent(); -// fprintf(stdout,"OBJECT END: %s\n",name); - continue; - } - } - -// -// read the triangles -// - for (i = 0; i < count; ++i) { - int j; - - fread( &tri, sizeof(tf_triangle), 1, input ); - ByteSwapTri (&tri); - for (j=0 ; j<3 ; j++) - { - int k; - - for (k=0 ; k<3 ; k++) - { - ptri->verts[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); - } - - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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 ; i<sizeof(tf_triangle)/4 ; i++) + { + ((int *)tri)[i] = BigLong (((int *)tri)[i]); + } +} + +void LoadTRI (char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes) +{ + FILE *input; + float start; + char name[256], tex[256]; + int i, count, magic; + tf_triangle tri; + triangle_t *ptri; + int iLevel; + int exitpattern; + float t; + + if (nodesList) + { + *num_mesh_nodes = 0; + *nodesList = (mesh_node_t *) SafeMalloc(MAX_FM_MESH_NODES * sizeof(mesh_node_t), "Mesh Node List"); + } + + 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); + + ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + + 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' ); + +// 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' ); + +// 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. */ + /* Mia culpa. */ + --iLevel; + i = -1; + do { + ++i; + fread( &(name[i]), sizeof( char ), 1, input); + } while( name[i] != '\0' ); + +// indent(); +// fprintf(stdout,"OBJECT END: %s\n",name); + continue; + } + } + +// +// read the triangles +// + for (i = 0; i < count; ++i) { + int j; + + fread( &tri, sizeof(tf_triangle), 1, input ); + ByteSwapTri (&tri); + for (j=0 ; j<3 ; j++) + { + int k; + + for (k=0 ; k<3 ; k++) + { + ptri->verts[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 index 2afdf559..5bceadde 100644 --- a/tools/quake2/qdata_heretic2/common/trilib.h +++ b/tools/quake2/qdata_heretic2/common/trilib.h @@ -1,56 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 6dd16355..273a482d 100644 --- a/tools/quake2/qdata_heretic2/fmodels.c +++ b/tools/quake2/qdata_heretic2/fmodels.c @@ -1,3404 +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 <assert.h> - -/* -======================================================================== - -.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 ; i<strlen(string); i++) - toupper(string[i]); - - return; -} - -#endif -//============================================================== - -/* -=============== -ClearModel -=============== -*/ -static void ClearModel (void) -{ - memset (&fmheader, 0, sizeof(fmheader)); - - modelname[0] = 0; - scale_up = 1.0; - VectorCopy (vec3_origin, adjust); - g_fixedwidth = g_fixedheight = 0; - g_skipmodel = false; - num_groups = 0; - - if (pmnodes) - { - free(pmnodes); - pmnodes = NULL; - } - - ClearSkeletalModel(); -} - - -extern void H_printf(char *fmt, ...); - - -void WriteHeader(FILE *FH, char *Ident, int Version, int Size, void *Data) -{ - header_t header; - static long pos = -1; - long CurrentPos; - - if (Size == 0) - { // Don't write out empty packets - return; - } - - if (pos != -1) - { - CurrentPos = ftell(FH); - Size = CurrentPos - pos + sizeof(header_t); - fseek(FH, pos, SEEK_SET); - pos = -2; - } - else if (Size == -1) - { - pos = ftell(FH); - } - - memset(&header,0,sizeof(header)); - strcpy(header.ident,Ident); - header.version = Version; - header.size = Size; - - SafeWrite (FH, &header, sizeof(header)); - - if (Data) - { - SafeWrite (FH, Data, Size); - } - - if (pos == -2) - { - pos = -1; - fseek(FH, 0, SEEK_END); - } -} - -/* -============ -WriteModelFile -============ -*/ -static void WriteModelFile (FILE *modelouthandle) -{ - int i; - int j, k; - fmframe_t *in; - fmaliasframe_t *out; - byte buffer[MAX_FM_VERTS*4+128]; - float v; - int c_on, c_off; - IntListNode_t *current, *toFree; - qboolean framesWritten = false; - size_t temp ,size = 0; - - // probably should do this dynamically one of these days - struct - { - float scale[3]; // multiply byte verts by this - float translate[3]; // then add this - } outFrames[MAX_FM_FRAMES]; - -#define DATA_SIZE 0x60000 // 384K had better be enough, particularly for the reference points - byte data[DATA_SIZE]; - byte data2[DATA_SIZE]; - - fmheader.num_glcmds = numcommands; - fmheader.framesize = (int)&((fmaliasframe_t *)0)->verts[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 ; i<fmheader.num_st ; i++) - { - base_st[i].s = LittleShort (base_st[i].s); - base_st[i].t = LittleShort (base_st[i].t); - } - - WriteHeader(modelouthandle, FM_ST_NAME, FM_ST_VER, fmheader.num_st * sizeof(base_st[0]), base_st); - - // - // write out the triangles - // - WriteHeader(modelouthandle, FM_TRI_NAME, FM_TRI_VER, fmheader.num_tris * sizeof(fmtriangle_t), NULL); - - for (i=0 ; i<fmheader.num_tris ; i++) - { - int j; - fmtriangle_t tri; - - for (j=0 ; j<3 ; j++) - { - tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); - tri.index_st[j] = LittleShort (triangles[i].index_st[j]); - } - - SafeWrite (modelouthandle, &tri, sizeof(tri)); - } - - if (!num_groups) - { - // - // write out the frames - // - WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, fmheader.num_frames * fmheader.framesize, NULL); - // WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL); - - for (i=0 ; i<fmheader.num_frames ; i++) - { - in = &g_frames[i]; - out = (fmaliasframe_t *)buffer; - - strcpy (out->name, 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 ; j<fmheader.num_xyz ; j++) - { - // all of these are byte values, so no need to deal with endianness - out->verts[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 ; i<fmheader.num_frames ; i++) - { - in = &g_frames[i]; - SafeWrite (modelouthandle,in->name,FRAME_NAME_LEN); - } - WriteHeader(modelouthandle, FM_NORMAL_NAME, FM_NORMAL_VER,fmheader.num_xyz, NULL); - in = &g_frames[0]; - for (j=0 ; j<fmheader.num_xyz ; j++) - SafeWrite (modelouthandle,&in->v[j].lightnormalindex,1); - } - - // - // write out glcmds - // - WriteHeader(modelouthandle, FM_GLCMDS_NAME, FM_GLCMDS_VER, numcommands*4, commands); - - // - // write out mesh nodes - // - for(i=0;i<fmheader.num_mesh_nodes;i++) - { - memcpy(mesh_nodes[i].tris, pmnodes[i].tris, sizeof(mesh_nodes[i].tris)); - memcpy(mesh_nodes[i].verts, pmnodes[i].verts, sizeof(mesh_nodes[i].verts)); - mesh_nodes[i].start_glcmds = LittleShort((short)pmnodes[i].start_glcmds); - mesh_nodes[i].num_glcmds = LittleShort((short)pmnodes[i].num_glcmds); - } - - WriteHeader(modelouthandle, FM_MESH_NAME, FM_MESH_VER, sizeof(fmmeshnode_t) * fmheader.num_mesh_nodes, mesh_nodes); - - if (num_groups) - { - -/* -typedef struct -{ - int start_frame; - int num_frames; - int degrees; - char *mat; fmheader.num_xyz*3*g->degrees*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;k<num_groups;k++) - { - g=&groups[k]; - size+=sizeof(int)*3; - size+=fmheader.num_xyz*3*g->degrees*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;k<num_groups;k++) - { - g=&groups[k]; - tmp=LittleLong(g->start_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<fmheader.num_frames;i++) - { - while (i>=groups[j].start_frame+groups[j].num_frames&&j<num_groups-1) - j++; - frame_to_group[i]=j; - } - - for (k=0;k<num_groups;k++) - { - g=&groups[k]; - - printf("\nCompressing Frames for group %i...\n", k); - AnimCompressInit(g->num_frames,fmheader.num_xyz,g->degrees); - for (i=0;i<g->num_frames;i++) - { - in = &g_frames[i+g->start_frame]; - for (j=0;j<fmheader.num_xyz;j++) - AnimSetFrame(i,j,in->v[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 ; i<fmheader.num_frames ; i++) - { - in = &g_frames[i]; - - for(j=0;j<fmheader.num_xyz;j++) - { - for(k=0,Found=false;k<j;k++) - { // starting from the beginning always ensures vert_replacement points to the first point in the array - if (in->v[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 ; i<fmheader.num_frames ; i++) - { - in = &g_frames[i]; - - for(j=0;j<fmheader.num_xyz;j++) - { - if (!vert_used[j]) - { - k = vert_replacement[j]; - - VectorAdd (in->v[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 ; j<fmheader.num_xyz ; j++) - { - vec3_t v; - float maxdot; - int maxdotindex; - int c; - - c = in->v[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<NUMVERTEXNORMALS ; k++) - { - float dot; - - dot = DotProduct (v, avertexnormals[k]); - if (dot > maxdot) - { - maxdot = dot; - maxdotindex = k; - } - } - - in->v[j].lightnormalindex = maxdotindex; - } - } - - // create substitution list - num_unique = 0; - for(i=0;i<fmheader.num_xyz;i++) - { - if (vert_used[i]) - { - vert_replacement[i] = num_unique; - num_unique++; - } - else - { - vert_replacement[i] = vert_replacement[vert_replacement[i]]; - } - - // vert_replacement[i] is the new index, i is the old index - // need to add the new index to the cluster list if old index was in it - if(g_skelModel.clustered == true) - { - 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) - { - 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 ; i<fmheader.num_frames ; i++) - { - in = &g_frames[i]; - - for(j=0;j<fmheader.num_xyz;j++) - { - in->v[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<fmheader.num_mesh_nodes;i++) - { // reset the vert bits - memset(pmnodes[i].verts,0,sizeof(pmnodes[i].verts)); - } - - // repleace the master triangle list vertex indexes and update the vert bits for each mesh node - for (i=0 ; i<fmheader.num_tris ; i++) - { - pos = 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;k<fmheader.num_mesh_nodes;k++) - { - if (!(pmnodes[k].tris[pos] & bit)) - { - continue; - } - pmnodes[k].verts[set_pos] |= set_bit; - } - } - } - - for (i=0;i<numcommands;i++) - { - j = commands[i]; - if (!j) continue; - - j = abs(j); - for(i++;j;j--,i+=3) - { - commands[i+2] = vert_replacement[commands[i+2]]; - } - i--; - } - - printf("Reduced by %d\n",fmheader.num_xyz - num_unique); - - fmheader.num_xyz = num_unique; - if (num_groups) - { - // tack on the reference verts to the regular verts - if(g_skelModel.references != REF_NULL) - { - fmframe_t *in; - int index; - int refnum; - - if (RefPointNum <= 0) - { // Hard-coded labels - refnum = numReferences[g_skelModel.references]; - } - else - { // Labels indicated in QDT - refnum = RefPointNum; - } - - - for (i = 0; i < fmheader.num_frames; ++i) - { - in = &g_frames[i]; - index = fmheader.num_xyz; - - for (j = 0 ; j < refnum; ++j) - { - VectorCopy(in->references[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<fmheader.num_skins ; i++) - { - ReleaseFile (g_skins[i]); - } - fmheader.num_frames = 0; - return; - } - - printf("\n"); - - trans_count = 0; - for(i=0;i<fmheader.num_tris;i++) - if (translucent[i]) - trans_count++; - - if (!g_no_opimizations) - { - OptimizeVertices(); - } - -// -// write the model output file -// - if (modelname[0]) - sprintf (name, "%s%s", g_outputDir, modelname); - else - sprintf (name, "%s/tris.fm", g_outputDir); - printf ("saving to %s\n", name); - CreatePath (name); - modelouthandle = SafeOpenWrite (name); - - WriteModelFile (modelouthandle); - - printf ("%3dx%3d skin\n", fmheader.skinwidth, fmheader.skinheight); - printf ("First frame boundaries:\n"); - printf (" minimum x: %3f\n", g_frames[0].mins[0]); - printf (" maximum x: %3f\n", g_frames[0].maxs[0]); - printf (" minimum y: %3f\n", g_frames[0].mins[1]); - printf (" maximum y: %3f\n", g_frames[0].maxs[1]); - printf (" minimum z: %3f\n", g_frames[0].mins[2]); - printf (" maximum z: %3f\n", g_frames[0].maxs[2]); - printf ("%4d vertices\n", fmheader.num_xyz); - printf ("%4d triangles, %4d of them translucent\n", fmheader.num_tris, trans_count); - printf ("%4d frame\n", fmheader.num_frames); - printf ("%4d glverts\n", numglverts); - printf ("%4d glcmd\n", fmheader.num_glcmds); - printf ("%4d skins\n", fmheader.num_skins); - printf ("%4d mesh nodes\n", fmheader.num_mesh_nodes); - printf ("wasted pixels: %d / %d (%5.2f Percent)\n",total_skin_pixels - skin_pixels_used, - total_skin_pixels, (double)(total_skin_pixels - skin_pixels_used) / (double)total_skin_pixels * 100.0); - - printf ("file size: %d\n", (int)ftell (modelouthandle) ); - printf ("---------------------\n"); - - if (g_verbose) - { - if (fmheader.num_mesh_nodes) - { - total_tris = total_verts = 0; - printf("Node Name Tris Verts\n"); - printf("--------------------------------- ---- -----\n"); - for(i=0;i<fmheader.num_mesh_nodes;i++) - { - tris = 0; - verts = 0; - for(j=0;j<MAXTRIANGLES;j++) - { - pos = (j) >> 3; - bit = 1 << ((j) & 7 ); - if (pmnodes[i].tris[pos] & bit) - { - tris++; - } - } - for(j=0;j<MAX_FM_VERTS;j++) - { - pos = (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;i<fmheader.num_mesh_nodes;i++) - { - strcpy(name, pmnodes[i].name); - strupr(name); - length = strlen(name); - for(j=0;j<length;j++) - { - if (name[j] == ' ') - { - name[j] = '_'; - } - } - H_printf("#define MESH_%s\t\t%d\n", name, i); - } - } - - fclose (headerouthandle); - headerouthandle = NULL; - free (pmnodes); -} - - -/* -================================================================= - -ALIAS MODEL DISPLAY LIST GENERATION - -================================================================= -*/ - -extern int strip_xyz[128]; -extern int strip_st[128]; -extern int strip_tris[128]; -extern int stripcount; - -/* -================ -StripLength -================ -*/ -static int StripLength (int starttri, int startv, int num_tris, int node) -{ - int m1, m2; - int st1, st2; - int j; - fmtriangle_t *last, *check; - int k; - int pos, bit; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<num_tris ; j++, check++) - { - pos = 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 ; j<num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - -/* -=========== -FanLength -=========== -*/ -static int FanLength (int starttri, int startv, int num_tris, int node) -{ - int m1, m2; - int st1, st2; - int j; - fmtriangle_t *last, *check; - int k; - int pos, bit; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<num_tris ; j++, check++) - { - pos = 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<num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - - -/* -================ -BuildGlCmds - -Generate a list of trifans or strips -for the model, which holds for all frames -================ -*/ -static void BuildGlCmds (void) -{ - int i, j, k, l; - int startv; - float s, t; - int len, bestlen, besttype; - int best_xyz[1024]; - int best_st[1024]; - int best_tris[1024]; - int type; - int trans_check; - int bit,pos; - - // - // build tristrips - // - numcommands = 0; - numglverts = 0; - - - for(l=0;l<fmheader.num_mesh_nodes;l++) - { - memset (used, 0, sizeof(used)); - - pmnodes[l].start_glcmds = numcommands; - - for(trans_check = 0; trans_check<2; trans_check++) - { - for (i=0 ; i < fmheader.num_tris ; i++) - { - pos = i >> 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<bestlen+2 ; j++) - { - best_st[j] = strip_st[j]; - best_xyz[j] = strip_xyz[j]; - } - for (j=0 ; j<bestlen ; j++) - best_tris[j] = strip_tris[j]; - } - } - } - - // mark the tris on the best strip/fan as used - for (j=0 ; j<bestlen ; j++) - used[best_tris[j]] = 1; - - if (besttype == 1) - commands[numcommands++] = (bestlen+2); - else - commands[numcommands++] = -(bestlen+2); - - numglverts += bestlen+2; - - for (j=0 ; j<bestlen+2 ; j++) - { - // emit a vertex into the reorder buffer - k = best_st[j]; - - // emit s/t coords into the commands stream - s = base_st[k].s; - t = base_st[k].t; - - s = (s ) / fmheader.skinwidth; - t = (t ) / fmheader.skinheight; - - *(float *)&commands[numcommands++] = s; - *(float *)&commands[numcommands++] = t; - *(int *)&commands[numcommands++] = best_xyz[j]; - } - } - } - commands[numcommands++] = 0; // end of list marker - pmnodes[l].num_glcmds = numcommands - pmnodes[l].start_glcmds; - } -} - - -/* -=============================================================== - -BASE FRAME SETUP - -=============================================================== -*/ - - -#define LINE_NORMAL 1 -#define LINE_FAT 2 -#define LINE_DOTTED 3 - - -#define ASCII_SPACE 32 - -int LineType = LINE_NORMAL; -extern unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768]; -unsigned char LineColor = 255; -int ScaleWidth, ScaleHeight; - - -static char *CharDefs[] = -{ - "-------------------------", - "-------------------------", // ! - "-------------------------", // " - "-------------------------", // # - "-------------------------", // $ - "-------------------------", // % - "-------------------------", // & - "--*----*-----------------", // ' - "-*---*----*----*-----*---", // ( - "*-----*----*----*---*----", // ) - "-----*--*--**---**--*--*-", // * - "-------------------------", // + - "----------------**--**---", // , - "-------------------------", // - - "----------------**---**--", // . - "-------------------------", // / - " *** * *** * *** * *** ", // 0 - " * ** * * * ", - "**** * *** * *****", - "**** * *** ***** ", - " ** * * * * ***** * ", - "**** * **** ***** ", - " *** * **** * * *** ", - "***** * * * * ", - " *** * * *** * * *** ", - " *** * * **** * *** ", // 9 - "-**---**--------**---**--", // : - "-------------------------", // ; - "-------------------------", // < - "-------------------------", // = - "-------------------------", // > - "-------------------------", // ? - "-------------------------", // @ - "-***-*---*******---**---*", // 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 <linetype> %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<numtri ; i++) - for (j=0 ; j<3 ; j++) - AddPointToBounds (ptri[i].verts[j], mins, maxs); - - for (i=0 ; i<3 ; i++) - { - mins[i] = floor(mins[i]); - maxs[i] = ceil(maxs[i]); - } - - width = maxs[0] - mins[0]; - height = maxs[2] - mins[2]; - - for (i=0 ; i<numtri ; i++) - { - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - if (normal[1] > 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<numtri ; i++) - { - if (ptri[i].HasUV) - { - for (j=0 ; j<3 ; j++) - { - triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*skinwidth); - triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*skinheight); - } - } - else - { - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - if (normal[1] > 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<numtri ; i++) - { - if (ptri[i].HasUV) - { - for (j=0 ; j<3 ; j++) - { - triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*(ScaleWidth-1)); - triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*(ScaleHeight-1)); - } - } - - 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 - - fmheader.skinwidth = (ScaleWidth + 3) & ~3; - fmheader.skinheight = ScaleHeight; - - skin_width = ScaleWidth; - skin_height = ScaleHeight; -} - - - - -byte *BasePalette; -byte *BasePixels,*TransPixels; -int BaseWidth, BaseHeight, TransWidth, TransHeight; -qboolean BaseTrueColor; -static qboolean SetPixel = false; - -int CheckTransRecursiveTri (int *lp1, int *lp2, int *lp3) -{ - int *temp; - int d; - int new[2]; - - d = lp2[0] - lp1[0]; - if (d < -1 || d > 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<fmheader.num_tris;i++) - { - ptri[i].HasUV=0; - } - } - - GetScriptToken (false); - sprintf (file2, "%s/%s", cddir, token); - sprintf (trans_file, "%s/!%s_a.pcx", cddir, token); - - ExtractFileExtension (file2, extension); - if (extension[0] == 0) - { - strcat(file2, ".pcx"); - } - printf ("skin: %s\n", file2); - - BaseTrueColor = LoadAnyImage (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight); - - NewSkin = false; - if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT) - { - if (g_allow_newskin) - { - ScaleWidth = BaseWidth; - ScaleHeight = BaseHeight; - NewSkin = true; - } - else - { - Error("Invalid skin page size: (%d,%d) should be (%d,%d)", - BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT); - } - } - else if (!BaseTrueColor) - { - ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X, - ENCODED_WIDTH_Y); - ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X, - ENCODED_HEIGHT_Y); - } - else - { - Error("Texture coordinates not supported on true color image"); - } - - if (GetST) - { - GetScriptToken (false); - - sprintf (stfile, "%s/%s.%s", cdarchive, token, trifileext); - printf ("ST: %s ", stfile); - - sprintf (stfile, "%s/%s", cddir, token); - - if (do3ds) - Load3DSTriangleList (stfile, &st_tri, &num_st_tris, NULL, NULL); - else - LoadTriangleList (stfile, &st_tri, &num_st_tris, NULL, NULL); - - if (num_st_tris != fmheader.num_tris) - { - Error ("num st tris mismatch: st %d / base %d", num_st_tris, fmheader.num_tris); - } - - printf(" matching triangles...\n"); - for(i=0;i<fmheader.num_tris;i++) - { - k = -1; - for(j=0;j<num_st_tris;j++) - { - for(x=0;x<3;x++) - { - for(y=0;y<3;y++) - { - if (x == y) - { - continue; - } - for(z=0;z<3;z++) - { - if (z == x || z == y) - { - continue; - } - - if (VectorFudgeCompare (ptri[i].verts[0], st_tri[j].verts[x]) && - VectorFudgeCompare (ptri[i].verts[1], st_tri[j].verts[y]) && - VectorFudgeCompare (ptri[i].verts[2], st_tri[j].verts[z])) - { - if (k == -1) - { - k = j; - ptri[i].HasUV = st_tri[k].HasUV; - ptri[i].uv[0][0] = st_tri[k].uv[x][0]; - ptri[i].uv[0][1] = st_tri[k].uv[x][1]; - ptri[i].uv[1][0] = st_tri[k].uv[y][0]; - ptri[i].uv[1][1] = st_tri[k].uv[y][1]; - ptri[i].uv[2][0] = st_tri[k].uv[z][0]; - ptri[i].uv[2][1] = st_tri[k].uv[z][1]; - x = y = z = 999; - } - else if (k != j) - { - printf("Duplicate triangle %d found in st file: %d and %d\n",i,k,j); - printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", - ptri[i].verts[0][0],ptri[i].verts[0][1],ptri[i].verts[0][2], - ptri[i].verts[1][0],ptri[i].verts[1][1],ptri[i].verts[1][2], - ptri[i].verts[2][0],ptri[i].verts[2][1],ptri[i].verts[2][2]); - printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", - st_tri[k].verts[0][0],st_tri[k].verts[0][1],st_tri[k].verts[0][2], - st_tri[k].verts[1][0],st_tri[k].verts[1][1],st_tri[k].verts[1][2], - st_tri[k].verts[2][0],st_tri[k].verts[2][1],st_tri[k].verts[2][2]); - printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", - st_tri[j].verts[0][0],st_tri[j].verts[0][1],st_tri[j].verts[0][2], - st_tri[j].verts[1][0],st_tri[j].verts[1][1],st_tri[j].verts[1][2], - st_tri[j].verts[2][0],st_tri[j].verts[2][1],st_tri[j].verts[2][2]); - } - } - } - } - } - } - if (k == -1) - { - printf("No matching triangle %d\n",i); - } - } - free (st_tri); - } - -// -// get the ST values -// - if (ptri && ptri[0].HasUV) - { - if (!NewSkin) - { - Error("Base has UVs with old style skin page\nMaybe you want to use -ignoreUV"); - } - else - { - BuildNewST (ptri, fmheader.num_tris, false); - } - } - else - { - if (NewSkin) - { - Error("Base has new style skin without UVs"); - } - else - { - BuildST (ptri, fmheader.num_tris, false); - } - } - - TransPixels = NULL; - if (!BaseTrueColor) - { - FH = fopen(trans_file,"rb"); - if (FH) - { - fclose(FH); - Load256Image (trans_file, &TransPixels, NULL, &TransWidth, &TransHeight); - if (TransWidth != fmheader.skinwidth || TransHeight != fmheader.skinheight) - { - Error ("source image %s dimensions (%d,%d) are not the same as alpha image (%d,%d)\n",file2,fmheader.skinwidth,fmheader.skinheight,TransWidth,TransHeight); - } - } - } - -// -// 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(l=0;l<fmheader.num_mesh_nodes;l++) - { - for (i=0 ; i < fmheader.num_tris ; i++) - { - pos = 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<fmheader.num_xyz ; k++) - { - if (VectorCompare (ptri[i].verts[j], base_xyz[k])) - { - break; // this vertex is already in the base vertex list - } - } - - if (k == fmheader.num_xyz) - { // new index - VectorCopy (ptri[i].verts[j], base_xyz[fmheader.num_xyz]); - - if(pmnodes[l].clustered == true) - { - ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&pmnodes[l].clusters, (IntListNode_t **)&g_skelModel.vertLists, (int *)&pmnodes[l].num_verts, (int *)&g_skelModel.new_num_verts); - } - - fmheader.num_xyz++; - } - - pos = 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_st ; k++) - { - if (triangle_st[i][j][0] == base_st[k].s - && triangle_st[i][j][1] == base_st[k].t) - { - break; // this vertex is already in the base vertex list - } - } - - if (k == fmheader.num_st) - { // new index - base_st[fmheader.num_st].s = triangle_st[i][j][0]; - base_st[fmheader.num_st].t = triangle_st[i][j][1]; - fmheader.num_st++; - } - - triangles[i].index_st[j] = k; - } - - if (TransPixels || BaseTrueColor) - { - translucent[i] = CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); - } - else - { - translucent[i] = false; - } - } - } - - if (!BaseTrueColor) - { - SetPixel = true; - memset(BasePixels,0,BaseWidth*BaseHeight); - for (i=0 ; i < fmheader.num_tris ; i++) - { - CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); - } - SetPixel = false; - - skin_pixels_used = 0; - for(i=0;i<fmheader.skinheight;i++) - { - for(j=0;j<fmheader.skinwidth;j++) - { - skin_pixels_used += BasePixels[(i*BaseWidth) + j]; - } - } - total_skin_pixels = fmheader.skinheight*fmheader.skinwidth; - } - else - { - SetPixel = true; - memset(BasePixels,0,BaseWidth*BaseHeight*4); - for (i=0 ; i < fmheader.num_tris ; i++) - { - CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); - } - SetPixel = false; - - skin_pixels_used = 0; - for(i=0;i<fmheader.skinheight;i++) - { - for(j=0;j<fmheader.skinwidth;j++) - { - skin_pixels_used += BasePixels[((i*BaseWidth) + j)*4]; - } - } - total_skin_pixels = fmheader.skinheight*fmheader.skinwidth; - } - - // build triangle strips / fans - BuildGlCmds (); - - if (TransPixels) - { - free(TransPixels); - } - free (BasePixels); - if (BasePalette) - { - free (BasePalette); - } - free(ptri); -} - -void Cmd_FMNodeOrder(void) -{ - mesh_node_t *newnodes, *pos; - int i,j; - - if (!pmnodes) - { - Error ("Base has not been established yet"); - } - - pos = newnodes = malloc(sizeof(mesh_node_t) * fmheader.num_mesh_nodes); - - for(i=0;i<fmheader.num_mesh_nodes;i++) - { - GetScriptToken (false); - - for(j=0;j<fmheader.num_mesh_nodes;j++) - { - if (strcmpi(pmnodes[j].name, token) == 0) - { - *pos = pmnodes[j]; - pos++; - break; - } - } - if (j >= 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 ; i<fmheader.num_xyz ; i++) - { - ptrivert[i].vnorm.numnormals = 0; - VectorClear (ptrivert[i].vnorm.normalsum); - } - ClearBounds (fr->mins, 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 ; i<num_tris ; i++) - { - vec3_t vtemp1, vtemp2, normal; - float ftemp; - - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - VectorNormalize (normal, normal); - - // rotate the normal so the model faces down the positive x axis - ftemp = normal[0]; - normal[0] = -normal[1]; - normal[1] = ftemp; - - for (j=0 ; j<3 ; j++) - { - index_xyz = triangles[i].index_xyz[j]; - - // rotate the vertices so the model faces down the positive x axis - // also adjust the vertices to the desired origin - ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + - adjust[0]; - ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + - adjust[1]; - ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + - adjust[2]; - - AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<fmheader.num_xyz ; i++) - { - int j; - vec3_t v; - float maxdot; - int maxdotindex; - int c; - - c = ptrivert[i].vnorm.numnormals; - if (!c) - Error ("Vertex with no triangles attached"); - - VectorScale (ptrivert[i].vnorm.normalsum, 1.0/c, v); - VectorNormalize (v, v); - - maxdot = -999999.0; - maxdotindex = -1; - - for (j=0 ; j<NUMVERTEXNORMALS ; j++) - { - float dot; - - dot = DotProduct (v, avertexnormals[j]); - if (dot > 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<fmheader.skinheight ; y++) - { - memcpy (cropped+y*fmheader.skinwidth, - pixels+y*width, fmheader.skinwidth); - } - - TransPixels = NULL; - FH = fopen(transname,"rb"); - if (FH) - { - fclose(FH); - - strcat(g_skins[fmheader.num_skins-1],".pcx"); - strcat(savename,".pcx"); - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette); - } - else - { - #if 1 - miptex_t *qtex; - qtex = CreateMip(cropped, fmheader.skinwidth, fmheader.skinheight, palette, &size, true); - - strcat(g_skins[fmheader.num_skins-1],".m8"); - strcat(savename,".m8"); - - printf ("saving %s\n", savename); - CreatePath (savename); - SaveFile (savename, (byte *)qtex, size); - free(qtex); - #else - strcat(g_skins[fmheader.num_skins-1],".pcx"); - strcat(savename,".pcx"); - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette); - #endif - } - } - else - { - cropped = (byte *) SafeMalloc (fmheader.skinwidth*fmheader.skinheight*4, "Cmd_FMSkin"); - for (y=0 ; y<fmheader.skinheight ; y++) - { - memcpy (cropped+((y*fmheader.skinwidth)*4), pixels+(y*width*4), fmheader.skinwidth*4); - } - - qtex32 = CreateMip32((unsigned *)cropped, fmheader.skinwidth, fmheader.skinheight, &size, true); - - StripExtension(g_skins[fmheader.num_skins-1]); - strcat(g_skins[fmheader.num_skins-1],".m32"); - StripExtension(savename); - strcat(savename,".m32"); - - printf ("saving %s\n", savename); - CreatePath (savename); - SaveFile (savename, (byte *)qtex32, size); - } - - free (pixels); - if (palette) - { - free (palette); - } - free (cropped); -} - - -/* -=============== -Cmd_Cd -=============== -*/ -void Cmd_FMCd (void) -{ - char temp[256]; - - FinishModel (); - ClearModel (); - - GetScriptToken (false); - - // this is a silly mess... - sprintf(cdpartial, "models/%s", token); - sprintf(cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); - sprintf(cddir, "%s%s", gamedir, cdpartial); - - // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too. - sprintf(temp, "%s%s", g_outputDir, cdpartial); - strcpy(g_outputDir, temp); - - // 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 monsters) - if (!g_only[0]) - return; - if (strncmp(token, g_only, strlen(g_only))) - { - g_skipmodel = true; - printf ("skipping %s\n", cdpartial); - } -} - - -/* - -//======================= -// NEW GEN -//======================= - -void NewGen (char *ModelFile, char *OutputName, int width, int height) -{ - trigroup_t *triangles; - triangle_t *ptri; - triangle_t *grouptris; - mesh_node_t *pmnodes; - - vec3_t *vertices; - vec3_t *uvs; - vec3_t aveNorm, crossvect; - vec3_t diffvect1, diffvect2; - vec3_t v0, v1, v2; - vec3_t n, u, v; - vec3_t base, zaxis, yaxis; - vec3_t uvwMin, uvwMax; - vec3_t groupMin, groupMax; - vec3_t uvw; - - float *uFinal, *vFinal; - unsigned char *newpic; - - int finalstart = 0, finalcount = 0; - int xbase = 0, xwidth = 0, ywidth = 0; - int *todo, *done, finished; - int i, j, k, l; //counters - int groupnum, numtris, numverts, num; - int count; - FILE *grpfile; - long datasize; - - for ( i = 0; i<3; i++) - { - aveNorm[i] = 0; - uvwMin[i] = 1e30f; - uvwMax[i] = -1e30f; - } - - pmnodes = NULL; - ptri = NULL; - triangles = NULL; - - zaxis[0] = 0; - zaxis[1] = 0; - zaxis[2] = 1; - - yaxis[0] = 0; - yaxis[1] = 1; - yaxis[2] = 0; - - LoadTriangleList (ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); - - todo = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen"); - done = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen"); - triangles = (trigroup_t*)SafeMalloc(fmheader.num_tris*sizeof(trigroup_t), "NewGen"); - - for ( i=0; i < fmheader.num_tris; i++) - { - todo[i] = false; - done[i] = false; - triangles[i].triangle = ptri[i]; - triangles[i].group = 0; - } - - groupnum = 0; - -// transitive closure algorithm follows -// put all triangles who transitively share vertices into separate groups - - while (1) - { - for ( i = 0; i < fmheader.num_tris; i++) - { - if (!done[i]) - { - break; - } - } - if ( i == fmheader.num_tris) - { - break; - } - finished = false; - todo[i] = true; - while (!finished) - { - finished = true; - for ( i = 0; i < fmheader.num_tris; i++) - { - if (todo[i]) - { - done[i] = true; - triangles[i].group = groupnum; - todo[i] = false; - for ( j = 0; j < fmheader.num_tris; j++) - { - if ((!done[j]) && (ShareVertex(triangles[i],triangles[j]))) - { - todo[j] = true; - finished = false; - } - } - } - } - } - groupnum++; - } - uFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen"); - vFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen"); - - grpfile = fopen("grpdebug.txt","w"); - - - for (i = 0; i < groupnum; i++) - { - - fprintf(grpfile,"Group Number: %d\n", i); - - numtris = GetNumTris(triangles, i); // number of triangles in group i - numverts = numtris * 3; - - fprintf(grpfile,"%d triangles.\n", numtris); - - vertices = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen"); - uvs = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen"); - grouptris = (triangle_t*)SafeMalloc(numtris*sizeof(triangle_t), "NewGen"); - - for (count = 0; count < fmheader.num_tris; count++) - { - if (triangles[count].group == i) - { - fprintf(grpfile,"Triangle %d\n", count); - } - } - fprintf(grpfile,"\n"); - - - - - GetOneGroup(triangles, i, grouptris); - - num = 0; - for (j = 0; j < numtris; j++) - { - VectorCopy(grouptris[j].verts[0], v0); - VectorCopy(grouptris[j].verts[1], v1); - VectorCopy(grouptris[j].verts[2], v2); - VectorSubtract(v1, v0, diffvect1); - VectorSubtract(v2, v1, diffvect2); - CrossProduct( diffvect1, diffvect2, crossvect); - VectorAdd(aveNorm, crossvect, aveNorm); - VectorCopy(v0,vertices[num]); - num++; // FIXME - VectorCopy(v1,vertices[num]); - num++; // add routine to add only verts that - VectorCopy(v2,vertices[num]); - num++; // have not already been added - } - - assert (num >= 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 <linetype> %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<verts; i++) - { - u[i] *= scale; - v[i] *= scale; - } - return; -} - - -void GetOneGroup(trigroup_t *tris, int grp, triangle_t* triangles) -{ - int i; - int j; - - j = 0; - for (i = 0; i < fmheader.num_tris; i++) - { - if (tris[i].group == grp) - { - triangles[j++] = tris[i].triangle; - } - } - return; -} - - -int GetNumTris( trigroup_t *tris, int grp) -{ - int i; - int verts; - - verts = 0; - for (i = 0; i < fmheader.num_tris; i++) - { - if (tris[i].group == grp) - { - verts++; - } - } - return verts; -} - - -int ShareVertex( trigroup_t trione, trigroup_t tritwo) -{ - int i; - int j; - - i = 1; - j = 1; - for ( i = 0; i < 3; i++) - { - for ( j = 0; j < 3; j++) - { - if (DistBetween(trione.triangle.verts[i],tritwo.triangle.verts[j]) < TRIVERT_DIST) - { - return true; - } - } - } - return false; -} - - -float DistBetween(vec3_t point1, vec3_t point2) -{ - float dist; - - dist = (point1[0] - point2[0]); - dist *= dist; - dist += (point1[1] - point2[1])*(point1[1]-point2[1]); - dist += (point1[2] - point2[2])*(point1[2]-point2[2]); - dist = sqrt(dist); - return dist; -} - - -void GenSkin(char *ModelFile, char *OutputName, int Width, int Height) -{ - triangle_t *ptri; - mesh_node_t *pmnodes; - int i; - - pmnodes = NULL; - ptri = NULL; - - LoadTriangleList (ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); - if (g_ignoreTriUV) - { - for (i=0;i<fmheader.num_tris;i++) - { - ptri[i].HasUV=0; - } - } - - memset(pic,0,sizeof(pic)); - memset(pic_palette,0,sizeof(pic_palette)); - pic_palette[767] = pic_palette[766] = pic_palette[765] = 255; - - ScaleWidth = Width; - ScaleHeight = Height; - - BuildST (ptri, fmheader.num_tris, true); - - WritePCXfile (OutputName, pic, SKINPAGE_WIDTH, SKINPAGE_HEIGHT, pic_palette); - - printf("Gen Skin Stats:\n"); - printf(" Input Base: %s\n",ModelFile); - printf(" Input Dimensions: %d,%d\n",Width,Height); - printf("\n"); - printf(" Output File: %s\n",OutputName); - printf(" Output Dimensions: %d,%d\n",ScaleWidth,ScaleHeight); - - if (fmheader.num_mesh_nodes) - { - printf("\nNodes:\n"); - for(i=0;i<fmheader.num_mesh_nodes;i++) - { - printf(" %s\n",pmnodes[i].name); - } - } - - free(ptri); - free(pmnodes); -} - - -void Cmd_FMBeginGroup (void) -{ - GetScriptToken (false); - - g_no_opimizations = false; - - groups[num_groups].start_frame = fmheader.num_frames; - groups[num_groups].num_frames = 0; - - groups[num_groups].degrees = atol(token); - if (groups[num_groups].degrees < 1 || groups[num_groups].degrees > 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); - } -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> + +/* +======================================================================== + +.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 ; i<strlen(string); i++) + toupper(string[i]); + + return; +} + +#endif +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +static void ClearModel (void) +{ + memset (&fmheader, 0, sizeof(fmheader)); + + modelname[0] = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; + num_groups = 0; + + if (pmnodes) + { + free(pmnodes); + pmnodes = NULL; + } + + ClearSkeletalModel(); +} + + +extern void H_printf(char *fmt, ...); + + +void WriteHeader(FILE *FH, char *Ident, int Version, int Size, void *Data) +{ + header_t header; + static long pos = -1; + long CurrentPos; + + if (Size == 0) + { // Don't write out empty packets + return; + } + + if (pos != -1) + { + CurrentPos = ftell(FH); + Size = CurrentPos - pos + sizeof(header_t); + fseek(FH, pos, SEEK_SET); + pos = -2; + } + else if (Size == -1) + { + pos = ftell(FH); + } + + memset(&header,0,sizeof(header)); + strcpy(header.ident,Ident); + header.version = Version; + header.size = Size; + + SafeWrite (FH, &header, sizeof(header)); + + if (Data) + { + SafeWrite (FH, Data, Size); + } + + if (pos == -2) + { + pos = -1; + fseek(FH, 0, SEEK_END); + } +} + +/* +============ +WriteModelFile +============ +*/ +static void WriteModelFile (FILE *modelouthandle) +{ + int i; + int j, k; + fmframe_t *in; + fmaliasframe_t *out; + byte buffer[MAX_FM_VERTS*4+128]; + float v; + int c_on, c_off; + IntListNode_t *current, *toFree; + qboolean framesWritten = false; + size_t temp ,size = 0; + + // probably should do this dynamically one of these days + struct + { + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + } outFrames[MAX_FM_FRAMES]; + +#define DATA_SIZE 0x60000 // 384K had better be enough, particularly for the reference points + byte data[DATA_SIZE]; + byte data2[DATA_SIZE]; + + fmheader.num_glcmds = numcommands; + fmheader.framesize = (int)&((fmaliasframe_t *)0)->verts[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 ; i<fmheader.num_st ; i++) + { + base_st[i].s = LittleShort (base_st[i].s); + base_st[i].t = LittleShort (base_st[i].t); + } + + WriteHeader(modelouthandle, FM_ST_NAME, FM_ST_VER, fmheader.num_st * sizeof(base_st[0]), base_st); + + // + // write out the triangles + // + WriteHeader(modelouthandle, FM_TRI_NAME, FM_TRI_VER, fmheader.num_tris * sizeof(fmtriangle_t), NULL); + + for (i=0 ; i<fmheader.num_tris ; i++) + { + int j; + fmtriangle_t tri; + + for (j=0 ; j<3 ; j++) + { + tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); + tri.index_st[j] = LittleShort (triangles[i].index_st[j]); + } + + SafeWrite (modelouthandle, &tri, sizeof(tri)); + } + + if (!num_groups) + { + // + // write out the frames + // + WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, fmheader.num_frames * fmheader.framesize, NULL); + // WriteHeader(modelouthandle, FM_FRAME_NAME, FM_FRAME_VER, -1, NULL); + + for (i=0 ; i<fmheader.num_frames ; i++) + { + in = &g_frames[i]; + out = (fmaliasframe_t *)buffer; + + strcpy (out->name, 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 ; j<fmheader.num_xyz ; j++) + { + // all of these are byte values, so no need to deal with endianness + out->verts[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 ; i<fmheader.num_frames ; i++) + { + in = &g_frames[i]; + SafeWrite (modelouthandle,in->name,FRAME_NAME_LEN); + } + WriteHeader(modelouthandle, FM_NORMAL_NAME, FM_NORMAL_VER,fmheader.num_xyz, NULL); + in = &g_frames[0]; + for (j=0 ; j<fmheader.num_xyz ; j++) + SafeWrite (modelouthandle,&in->v[j].lightnormalindex,1); + } + + // + // write out glcmds + // + WriteHeader(modelouthandle, FM_GLCMDS_NAME, FM_GLCMDS_VER, numcommands*4, commands); + + // + // write out mesh nodes + // + for(i=0;i<fmheader.num_mesh_nodes;i++) + { + memcpy(mesh_nodes[i].tris, pmnodes[i].tris, sizeof(mesh_nodes[i].tris)); + memcpy(mesh_nodes[i].verts, pmnodes[i].verts, sizeof(mesh_nodes[i].verts)); + mesh_nodes[i].start_glcmds = LittleShort((short)pmnodes[i].start_glcmds); + mesh_nodes[i].num_glcmds = LittleShort((short)pmnodes[i].num_glcmds); + } + + WriteHeader(modelouthandle, FM_MESH_NAME, FM_MESH_VER, sizeof(fmmeshnode_t) * fmheader.num_mesh_nodes, mesh_nodes); + + if (num_groups) + { + +/* +typedef struct +{ + int start_frame; + int num_frames; + int degrees; + char *mat; fmheader.num_xyz*3*g->degrees*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;k<num_groups;k++) + { + g=&groups[k]; + size+=sizeof(int)*3; + size+=fmheader.num_xyz*3*g->degrees*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;k<num_groups;k++) + { + g=&groups[k]; + tmp=LittleLong(g->start_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<fmheader.num_frames;i++) + { + while (i>=groups[j].start_frame+groups[j].num_frames&&j<num_groups-1) + j++; + frame_to_group[i]=j; + } + + for (k=0;k<num_groups;k++) + { + g=&groups[k]; + + printf("\nCompressing Frames for group %i...\n", k); + AnimCompressInit(g->num_frames,fmheader.num_xyz,g->degrees); + for (i=0;i<g->num_frames;i++) + { + in = &g_frames[i+g->start_frame]; + for (j=0;j<fmheader.num_xyz;j++) + AnimSetFrame(i,j,in->v[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 ; i<fmheader.num_frames ; i++) + { + in = &g_frames[i]; + + for(j=0;j<fmheader.num_xyz;j++) + { + for(k=0,Found=false;k<j;k++) + { // starting from the beginning always ensures vert_replacement points to the first point in the array + if (in->v[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 ; i<fmheader.num_frames ; i++) + { + in = &g_frames[i]; + + for(j=0;j<fmheader.num_xyz;j++) + { + if (!vert_used[j]) + { + k = vert_replacement[j]; + + VectorAdd (in->v[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 ; j<fmheader.num_xyz ; j++) + { + vec3_t v; + float maxdot; + int maxdotindex; + int c; + + c = in->v[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<NUMVERTEXNORMALS ; k++) + { + float dot; + + dot = DotProduct (v, avertexnormals[k]); + if (dot > maxdot) + { + maxdot = dot; + maxdotindex = k; + } + } + + in->v[j].lightnormalindex = maxdotindex; + } + } + + // create substitution list + num_unique = 0; + for(i=0;i<fmheader.num_xyz;i++) + { + if (vert_used[i]) + { + vert_replacement[i] = num_unique; + num_unique++; + } + else + { + vert_replacement[i] = vert_replacement[vert_replacement[i]]; + } + + // vert_replacement[i] is the new index, i is the old index + // need to add the new index to the cluster list if old index was in it + if(g_skelModel.clustered == true) + { + 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) + { + 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 ; i<fmheader.num_frames ; i++) + { + in = &g_frames[i]; + + for(j=0;j<fmheader.num_xyz;j++) + { + in->v[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<fmheader.num_mesh_nodes;i++) + { // reset the vert bits + memset(pmnodes[i].verts,0,sizeof(pmnodes[i].verts)); + } + + // repleace the master triangle list vertex indexes and update the vert bits for each mesh node + for (i=0 ; i<fmheader.num_tris ; i++) + { + pos = 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;k<fmheader.num_mesh_nodes;k++) + { + if (!(pmnodes[k].tris[pos] & bit)) + { + continue; + } + pmnodes[k].verts[set_pos] |= set_bit; + } + } + } + + for (i=0;i<numcommands;i++) + { + j = commands[i]; + if (!j) continue; + + j = abs(j); + for(i++;j;j--,i+=3) + { + commands[i+2] = vert_replacement[commands[i+2]]; + } + i--; + } + + printf("Reduced by %d\n",fmheader.num_xyz - num_unique); + + fmheader.num_xyz = num_unique; + if (num_groups) + { + // tack on the reference verts to the regular verts + if(g_skelModel.references != REF_NULL) + { + fmframe_t *in; + int index; + int refnum; + + if (RefPointNum <= 0) + { // Hard-coded labels + refnum = numReferences[g_skelModel.references]; + } + else + { // Labels indicated in QDT + refnum = RefPointNum; + } + + + for (i = 0; i < fmheader.num_frames; ++i) + { + in = &g_frames[i]; + index = fmheader.num_xyz; + + for (j = 0 ; j < refnum; ++j) + { + VectorCopy(in->references[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<fmheader.num_skins ; i++) + { + ReleaseFile (g_skins[i]); + } + fmheader.num_frames = 0; + return; + } + + printf("\n"); + + trans_count = 0; + for(i=0;i<fmheader.num_tris;i++) + if (translucent[i]) + trans_count++; + + if (!g_no_opimizations) + { + OptimizeVertices(); + } + +// +// write the model output file +// + if (modelname[0]) + sprintf (name, "%s%s", g_outputDir, modelname); + else + sprintf (name, "%s/tris.fm", g_outputDir); + printf ("saving to %s\n", name); + CreatePath (name); + modelouthandle = SafeOpenWrite (name); + + WriteModelFile (modelouthandle); + + printf ("%3dx%3d skin\n", fmheader.skinwidth, fmheader.skinheight); + printf ("First frame boundaries:\n"); + printf (" minimum x: %3f\n", g_frames[0].mins[0]); + printf (" maximum x: %3f\n", g_frames[0].maxs[0]); + printf (" minimum y: %3f\n", g_frames[0].mins[1]); + printf (" maximum y: %3f\n", g_frames[0].maxs[1]); + printf (" minimum z: %3f\n", g_frames[0].mins[2]); + printf (" maximum z: %3f\n", g_frames[0].maxs[2]); + printf ("%4d vertices\n", fmheader.num_xyz); + printf ("%4d triangles, %4d of them translucent\n", fmheader.num_tris, trans_count); + printf ("%4d frame\n", fmheader.num_frames); + printf ("%4d glverts\n", numglverts); + printf ("%4d glcmd\n", fmheader.num_glcmds); + printf ("%4d skins\n", fmheader.num_skins); + printf ("%4d mesh nodes\n", fmheader.num_mesh_nodes); + printf ("wasted pixels: %d / %d (%5.2f Percent)\n",total_skin_pixels - skin_pixels_used, + total_skin_pixels, (double)(total_skin_pixels - skin_pixels_used) / (double)total_skin_pixels * 100.0); + + printf ("file size: %d\n", (int)ftell (modelouthandle) ); + printf ("---------------------\n"); + + if (g_verbose) + { + if (fmheader.num_mesh_nodes) + { + total_tris = total_verts = 0; + printf("Node Name Tris Verts\n"); + printf("--------------------------------- ---- -----\n"); + for(i=0;i<fmheader.num_mesh_nodes;i++) + { + tris = 0; + verts = 0; + for(j=0;j<MAXTRIANGLES;j++) + { + pos = (j) >> 3; + bit = 1 << ((j) & 7 ); + if (pmnodes[i].tris[pos] & bit) + { + tris++; + } + } + for(j=0;j<MAX_FM_VERTS;j++) + { + pos = (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;i<fmheader.num_mesh_nodes;i++) + { + strcpy(name, pmnodes[i].name); + strupr(name); + length = strlen(name); + for(j=0;j<length;j++) + { + if (name[j] == ' ') + { + name[j] = '_'; + } + } + H_printf("#define MESH_%s\t\t%d\n", name, i); + } + } + + fclose (headerouthandle); + headerouthandle = NULL; + free (pmnodes); +} + + +/* +================================================================= + +ALIAS MODEL DISPLAY LIST GENERATION + +================================================================= +*/ + +extern int strip_xyz[128]; +extern int strip_st[128]; +extern int strip_tris[128]; +extern int stripcount; + +/* +================ +StripLength +================ +*/ +static int StripLength (int starttri, int startv, int num_tris, int node) +{ + int m1, m2; + int st1, st2; + int j; + fmtriangle_t *last, *check; + int k; + int pos, bit; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<num_tris ; j++, check++) + { + pos = 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 ; j<num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + +/* +=========== +FanLength +=========== +*/ +static int FanLength (int starttri, int startv, int num_tris, int node) +{ + int m1, m2; + int st1, st2; + int j; + fmtriangle_t *last, *check; + int k; + int pos, bit; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<num_tris ; j++, check++) + { + pos = 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<num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + + +/* +================ +BuildGlCmds + +Generate a list of trifans or strips +for the model, which holds for all frames +================ +*/ +static void BuildGlCmds (void) +{ + int i, j, k, l; + int startv; + float s, t; + int len, bestlen, besttype; + int best_xyz[1024]; + int best_st[1024]; + int best_tris[1024]; + int type; + int trans_check; + int bit,pos; + + // + // build tristrips + // + numcommands = 0; + numglverts = 0; + + + for(l=0;l<fmheader.num_mesh_nodes;l++) + { + memset (used, 0, sizeof(used)); + + pmnodes[l].start_glcmds = numcommands; + + for(trans_check = 0; trans_check<2; trans_check++) + { + for (i=0 ; i < fmheader.num_tris ; i++) + { + pos = i >> 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<bestlen+2 ; j++) + { + best_st[j] = strip_st[j]; + best_xyz[j] = strip_xyz[j]; + } + for (j=0 ; j<bestlen ; j++) + best_tris[j] = strip_tris[j]; + } + } + } + + // mark the tris on the best strip/fan as used + for (j=0 ; j<bestlen ; j++) + used[best_tris[j]] = 1; + + if (besttype == 1) + commands[numcommands++] = (bestlen+2); + else + commands[numcommands++] = -(bestlen+2); + + numglverts += bestlen+2; + + for (j=0 ; j<bestlen+2 ; j++) + { + // emit a vertex into the reorder buffer + k = best_st[j]; + + // emit s/t coords into the commands stream + s = base_st[k].s; + t = base_st[k].t; + + s = (s ) / fmheader.skinwidth; + t = (t ) / fmheader.skinheight; + + *(float *)&commands[numcommands++] = s; + *(float *)&commands[numcommands++] = t; + *(int *)&commands[numcommands++] = best_xyz[j]; + } + } + } + commands[numcommands++] = 0; // end of list marker + pmnodes[l].num_glcmds = numcommands - pmnodes[l].start_glcmds; + } +} + + +/* +=============================================================== + +BASE FRAME SETUP + +=============================================================== +*/ + + +#define LINE_NORMAL 1 +#define LINE_FAT 2 +#define LINE_DOTTED 3 + + +#define ASCII_SPACE 32 + +int LineType = LINE_NORMAL; +extern unsigned char pic[SKINPAGE_HEIGHT*SKINPAGE_WIDTH], pic_palette[768]; +unsigned char LineColor = 255; +int ScaleWidth, ScaleHeight; + + +static char *CharDefs[] = +{ + "-------------------------", + "-------------------------", // ! + "-------------------------", // " + "-------------------------", // # + "-------------------------", // $ + "-------------------------", // % + "-------------------------", // & + "--*----*-----------------", // ' + "-*---*----*----*-----*---", // ( + "*-----*----*----*---*----", // ) + "-----*--*--**---**--*--*-", // * + "-------------------------", // + + "----------------**--**---", // , + "-------------------------", // - + "----------------**---**--", // . + "-------------------------", // / + " *** * *** * *** * *** ", // 0 + " * ** * * * ", + "**** * *** * *****", + "**** * *** ***** ", + " ** * * * * ***** * ", + "**** * **** ***** ", + " *** * **** * * *** ", + "***** * * * * ", + " *** * * *** * * *** ", + " *** * * **** * *** ", // 9 + "-**---**--------**---**--", // : + "-------------------------", // ; + "-------------------------", // < + "-------------------------", // = + "-------------------------", // > + "-------------------------", // ? + "-------------------------", // @ + "-***-*---*******---**---*", // 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 <linetype> %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<numtri ; i++) + for (j=0 ; j<3 ; j++) + AddPointToBounds (ptri[i].verts[j], mins, maxs); + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + for (i=0 ; i<numtri ; i++) + { + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + if (normal[1] > 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<numtri ; i++) + { + if (ptri[i].HasUV) + { + for (j=0 ; j<3 ; j++) + { + triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*skinwidth); + triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*skinheight); + } + } + else + { + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + if (normal[1] > 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<numtri ; i++) + { + if (ptri[i].HasUV) + { + for (j=0 ; j<3 ; j++) + { + triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*(ScaleWidth-1)); + triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*(ScaleHeight-1)); + } + } + + 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 + + fmheader.skinwidth = (ScaleWidth + 3) & ~3; + fmheader.skinheight = ScaleHeight; + + skin_width = ScaleWidth; + skin_height = ScaleHeight; +} + + + + +byte *BasePalette; +byte *BasePixels,*TransPixels; +int BaseWidth, BaseHeight, TransWidth, TransHeight; +qboolean BaseTrueColor; +static qboolean SetPixel = false; + +int CheckTransRecursiveTri (int *lp1, int *lp2, int *lp3) +{ + int *temp; + int d; + int new[2]; + + d = lp2[0] - lp1[0]; + if (d < -1 || d > 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<fmheader.num_tris;i++) + { + ptri[i].HasUV=0; + } + } + + GetScriptToken (false); + sprintf (file2, "%s/%s", cddir, token); + sprintf (trans_file, "%s/!%s_a.pcx", cddir, token); + + ExtractFileExtension (file2, extension); + if (extension[0] == 0) + { + strcat(file2, ".pcx"); + } + printf ("skin: %s\n", file2); + + BaseTrueColor = LoadAnyImage (file2, &BasePixels, &BasePalette, &BaseWidth, &BaseHeight); + + NewSkin = false; + if (BaseWidth != SKINPAGE_WIDTH || BaseHeight != SKINPAGE_HEIGHT) + { + if (g_allow_newskin) + { + ScaleWidth = BaseWidth; + ScaleHeight = BaseHeight; + NewSkin = true; + } + else + { + Error("Invalid skin page size: (%d,%d) should be (%d,%d)", + BaseWidth,BaseHeight,SKINPAGE_WIDTH,SKINPAGE_HEIGHT); + } + } + else if (!BaseTrueColor) + { + ScaleWidth = (float)ExtractNumber(BasePixels, ENCODED_WIDTH_X, + ENCODED_WIDTH_Y); + ScaleHeight = (float)ExtractNumber(BasePixels, ENCODED_HEIGHT_X, + ENCODED_HEIGHT_Y); + } + else + { + Error("Texture coordinates not supported on true color image"); + } + + if (GetST) + { + GetScriptToken (false); + + sprintf (stfile, "%s/%s.%s", cdarchive, token, trifileext); + printf ("ST: %s ", stfile); + + sprintf (stfile, "%s/%s", cddir, token); + + if (do3ds) + Load3DSTriangleList (stfile, &st_tri, &num_st_tris, NULL, NULL); + else + LoadTriangleList (stfile, &st_tri, &num_st_tris, NULL, NULL); + + if (num_st_tris != fmheader.num_tris) + { + Error ("num st tris mismatch: st %d / base %d", num_st_tris, fmheader.num_tris); + } + + printf(" matching triangles...\n"); + for(i=0;i<fmheader.num_tris;i++) + { + k = -1; + for(j=0;j<num_st_tris;j++) + { + for(x=0;x<3;x++) + { + for(y=0;y<3;y++) + { + if (x == y) + { + continue; + } + for(z=0;z<3;z++) + { + if (z == x || z == y) + { + continue; + } + + if (VectorFudgeCompare (ptri[i].verts[0], st_tri[j].verts[x]) && + VectorFudgeCompare (ptri[i].verts[1], st_tri[j].verts[y]) && + VectorFudgeCompare (ptri[i].verts[2], st_tri[j].verts[z])) + { + if (k == -1) + { + k = j; + ptri[i].HasUV = st_tri[k].HasUV; + ptri[i].uv[0][0] = st_tri[k].uv[x][0]; + ptri[i].uv[0][1] = st_tri[k].uv[x][1]; + ptri[i].uv[1][0] = st_tri[k].uv[y][0]; + ptri[i].uv[1][1] = st_tri[k].uv[y][1]; + ptri[i].uv[2][0] = st_tri[k].uv[z][0]; + ptri[i].uv[2][1] = st_tri[k].uv[z][1]; + x = y = z = 999; + } + else if (k != j) + { + printf("Duplicate triangle %d found in st file: %d and %d\n",i,k,j); + printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", + ptri[i].verts[0][0],ptri[i].verts[0][1],ptri[i].verts[0][2], + ptri[i].verts[1][0],ptri[i].verts[1][1],ptri[i].verts[1][2], + ptri[i].verts[2][0],ptri[i].verts[2][1],ptri[i].verts[2][2]); + printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", + st_tri[k].verts[0][0],st_tri[k].verts[0][1],st_tri[k].verts[0][2], + st_tri[k].verts[1][0],st_tri[k].verts[1][1],st_tri[k].verts[1][2], + st_tri[k].verts[2][0],st_tri[k].verts[2][1],st_tri[k].verts[2][2]); + printf(" (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f) (%0.3f %0.3f %0.3f)\n", + st_tri[j].verts[0][0],st_tri[j].verts[0][1],st_tri[j].verts[0][2], + st_tri[j].verts[1][0],st_tri[j].verts[1][1],st_tri[j].verts[1][2], + st_tri[j].verts[2][0],st_tri[j].verts[2][1],st_tri[j].verts[2][2]); + } + } + } + } + } + } + if (k == -1) + { + printf("No matching triangle %d\n",i); + } + } + free (st_tri); + } + +// +// get the ST values +// + if (ptri && ptri[0].HasUV) + { + if (!NewSkin) + { + Error("Base has UVs with old style skin page\nMaybe you want to use -ignoreUV"); + } + else + { + BuildNewST (ptri, fmheader.num_tris, false); + } + } + else + { + if (NewSkin) + { + Error("Base has new style skin without UVs"); + } + else + { + BuildST (ptri, fmheader.num_tris, false); + } + } + + TransPixels = NULL; + if (!BaseTrueColor) + { + FH = fopen(trans_file,"rb"); + if (FH) + { + fclose(FH); + Load256Image (trans_file, &TransPixels, NULL, &TransWidth, &TransHeight); + if (TransWidth != fmheader.skinwidth || TransHeight != fmheader.skinheight) + { + Error ("source image %s dimensions (%d,%d) are not the same as alpha image (%d,%d)\n",file2,fmheader.skinwidth,fmheader.skinheight,TransWidth,TransHeight); + } + } + } + +// +// 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(l=0;l<fmheader.num_mesh_nodes;l++) + { + for (i=0 ; i < fmheader.num_tris ; i++) + { + pos = 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<fmheader.num_xyz ; k++) + { + if (VectorCompare (ptri[i].verts[j], base_xyz[k])) + { + break; // this vertex is already in the base vertex list + } + } + + if (k == fmheader.num_xyz) + { // new index + VectorCopy (ptri[i].verts[j], base_xyz[fmheader.num_xyz]); + + if(pmnodes[l].clustered == true) + { + ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&pmnodes[l].clusters, (IntListNode_t **)&g_skelModel.vertLists, (int *)&pmnodes[l].num_verts, (int *)&g_skelModel.new_num_verts); + } + + fmheader.num_xyz++; + } + + pos = 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_st ; k++) + { + if (triangle_st[i][j][0] == base_st[k].s + && triangle_st[i][j][1] == base_st[k].t) + { + break; // this vertex is already in the base vertex list + } + } + + if (k == fmheader.num_st) + { // new index + base_st[fmheader.num_st].s = triangle_st[i][j][0]; + base_st[fmheader.num_st].t = triangle_st[i][j][1]; + fmheader.num_st++; + } + + triangles[i].index_st[j] = k; + } + + if (TransPixels || BaseTrueColor) + { + translucent[i] = CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); + } + else + { + translucent[i] = false; + } + } + } + + if (!BaseTrueColor) + { + SetPixel = true; + memset(BasePixels,0,BaseWidth*BaseHeight); + for (i=0 ; i < fmheader.num_tris ; i++) + { + CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); + } + SetPixel = false; + + skin_pixels_used = 0; + for(i=0;i<fmheader.skinheight;i++) + { + for(j=0;j<fmheader.skinwidth;j++) + { + skin_pixels_used += BasePixels[(i*BaseWidth) + j]; + } + } + total_skin_pixels = fmheader.skinheight*fmheader.skinwidth; + } + else + { + SetPixel = true; + memset(BasePixels,0,BaseWidth*BaseHeight*4); + for (i=0 ; i < fmheader.num_tris ; i++) + { + CheckTransRecursiveTri(triangle_st[i][0], triangle_st[i][1], triangle_st[i][2]); + } + SetPixel = false; + + skin_pixels_used = 0; + for(i=0;i<fmheader.skinheight;i++) + { + for(j=0;j<fmheader.skinwidth;j++) + { + skin_pixels_used += BasePixels[((i*BaseWidth) + j)*4]; + } + } + total_skin_pixels = fmheader.skinheight*fmheader.skinwidth; + } + + // build triangle strips / fans + BuildGlCmds (); + + if (TransPixels) + { + free(TransPixels); + } + free (BasePixels); + if (BasePalette) + { + free (BasePalette); + } + free(ptri); +} + +void Cmd_FMNodeOrder(void) +{ + mesh_node_t *newnodes, *pos; + int i,j; + + if (!pmnodes) + { + Error ("Base has not been established yet"); + } + + pos = newnodes = malloc(sizeof(mesh_node_t) * fmheader.num_mesh_nodes); + + for(i=0;i<fmheader.num_mesh_nodes;i++) + { + GetScriptToken (false); + + for(j=0;j<fmheader.num_mesh_nodes;j++) + { + if (strcmpi(pmnodes[j].name, token) == 0) + { + *pos = pmnodes[j]; + pos++; + break; + } + } + if (j >= 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 ; i<fmheader.num_xyz ; i++) + { + ptrivert[i].vnorm.numnormals = 0; + VectorClear (ptrivert[i].vnorm.normalsum); + } + ClearBounds (fr->mins, 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 ; i<num_tris ; i++) + { + vec3_t vtemp1, vtemp2, normal; + float ftemp; + + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + VectorNormalize (normal, normal); + + // rotate the normal so the model faces down the positive x axis + ftemp = normal[0]; + normal[0] = -normal[1]; + normal[1] = ftemp; + + for (j=0 ; j<3 ; j++) + { + index_xyz = triangles[i].index_xyz[j]; + + // rotate the vertices so the model faces down the positive x axis + // also adjust the vertices to the desired origin + ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + + adjust[0]; + ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + + adjust[1]; + ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + + adjust[2]; + + AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<fmheader.num_xyz ; i++) + { + int j; + vec3_t v; + float maxdot; + int maxdotindex; + int c; + + c = ptrivert[i].vnorm.numnormals; + if (!c) + Error ("Vertex with no triangles attached"); + + VectorScale (ptrivert[i].vnorm.normalsum, 1.0/c, v); + VectorNormalize (v, v); + + maxdot = -999999.0; + maxdotindex = -1; + + for (j=0 ; j<NUMVERTEXNORMALS ; j++) + { + float dot; + + dot = DotProduct (v, avertexnormals[j]); + if (dot > 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<fmheader.skinheight ; y++) + { + memcpy (cropped+y*fmheader.skinwidth, + pixels+y*width, fmheader.skinwidth); + } + + TransPixels = NULL; + FH = fopen(transname,"rb"); + if (FH) + { + fclose(FH); + + strcat(g_skins[fmheader.num_skins-1],".pcx"); + strcat(savename,".pcx"); + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette); + } + else + { + #if 1 + miptex_t *qtex; + qtex = CreateMip(cropped, fmheader.skinwidth, fmheader.skinheight, palette, &size, true); + + strcat(g_skins[fmheader.num_skins-1],".m8"); + strcat(savename,".m8"); + + printf ("saving %s\n", savename); + CreatePath (savename); + SaveFile (savename, (byte *)qtex, size); + free(qtex); + #else + strcat(g_skins[fmheader.num_skins-1],".pcx"); + strcat(savename,".pcx"); + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, fmheader.skinwidth, fmheader.skinheight, palette); + #endif + } + } + else + { + cropped = (byte *) SafeMalloc (fmheader.skinwidth*fmheader.skinheight*4, "Cmd_FMSkin"); + for (y=0 ; y<fmheader.skinheight ; y++) + { + memcpy (cropped+((y*fmheader.skinwidth)*4), pixels+(y*width*4), fmheader.skinwidth*4); + } + + qtex32 = CreateMip32((unsigned *)cropped, fmheader.skinwidth, fmheader.skinheight, &size, true); + + StripExtension(g_skins[fmheader.num_skins-1]); + strcat(g_skins[fmheader.num_skins-1],".m32"); + StripExtension(savename); + strcat(savename,".m32"); + + printf ("saving %s\n", savename); + CreatePath (savename); + SaveFile (savename, (byte *)qtex32, size); + } + + free (pixels); + if (palette) + { + free (palette); + } + free (cropped); +} + + +/* +=============== +Cmd_Cd +=============== +*/ +void Cmd_FMCd (void) +{ + char temp[256]; + + FinishModel (); + ClearModel (); + + GetScriptToken (false); + + // this is a silly mess... + sprintf(cdpartial, "models/%s", token); + sprintf(cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); + sprintf(cddir, "%s%s", gamedir, cdpartial); + + // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too. + sprintf(temp, "%s%s", g_outputDir, cdpartial); + strcpy(g_outputDir, temp); + + // 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 monsters) + if (!g_only[0]) + return; + if (strncmp(token, g_only, strlen(g_only))) + { + g_skipmodel = true; + printf ("skipping %s\n", cdpartial); + } +} + + +/* + +//======================= +// NEW GEN +//======================= + +void NewGen (char *ModelFile, char *OutputName, int width, int height) +{ + trigroup_t *triangles; + triangle_t *ptri; + triangle_t *grouptris; + mesh_node_t *pmnodes; + + vec3_t *vertices; + vec3_t *uvs; + vec3_t aveNorm, crossvect; + vec3_t diffvect1, diffvect2; + vec3_t v0, v1, v2; + vec3_t n, u, v; + vec3_t base, zaxis, yaxis; + vec3_t uvwMin, uvwMax; + vec3_t groupMin, groupMax; + vec3_t uvw; + + float *uFinal, *vFinal; + unsigned char *newpic; + + int finalstart = 0, finalcount = 0; + int xbase = 0, xwidth = 0, ywidth = 0; + int *todo, *done, finished; + int i, j, k, l; //counters + int groupnum, numtris, numverts, num; + int count; + FILE *grpfile; + long datasize; + + for ( i = 0; i<3; i++) + { + aveNorm[i] = 0; + uvwMin[i] = 1e30f; + uvwMax[i] = -1e30f; + } + + pmnodes = NULL; + ptri = NULL; + triangles = NULL; + + zaxis[0] = 0; + zaxis[1] = 0; + zaxis[2] = 1; + + yaxis[0] = 0; + yaxis[1] = 1; + yaxis[2] = 0; + + LoadTriangleList (ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + + todo = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen"); + done = (int*)SafeMalloc(fmheader.num_tris*sizeof(int), "NewGen"); + triangles = (trigroup_t*)SafeMalloc(fmheader.num_tris*sizeof(trigroup_t), "NewGen"); + + for ( i=0; i < fmheader.num_tris; i++) + { + todo[i] = false; + done[i] = false; + triangles[i].triangle = ptri[i]; + triangles[i].group = 0; + } + + groupnum = 0; + +// transitive closure algorithm follows +// put all triangles who transitively share vertices into separate groups + + while (1) + { + for ( i = 0; i < fmheader.num_tris; i++) + { + if (!done[i]) + { + break; + } + } + if ( i == fmheader.num_tris) + { + break; + } + finished = false; + todo[i] = true; + while (!finished) + { + finished = true; + for ( i = 0; i < fmheader.num_tris; i++) + { + if (todo[i]) + { + done[i] = true; + triangles[i].group = groupnum; + todo[i] = false; + for ( j = 0; j < fmheader.num_tris; j++) + { + if ((!done[j]) && (ShareVertex(triangles[i],triangles[j]))) + { + todo[j] = true; + finished = false; + } + } + } + } + } + groupnum++; + } + uFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen"); + vFinal = (float*)SafeMalloc(3*fmheader.num_tris*sizeof(float), "NewGen"); + + grpfile = fopen("grpdebug.txt","w"); + + + for (i = 0; i < groupnum; i++) + { + + fprintf(grpfile,"Group Number: %d\n", i); + + numtris = GetNumTris(triangles, i); // number of triangles in group i + numverts = numtris * 3; + + fprintf(grpfile,"%d triangles.\n", numtris); + + vertices = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen"); + uvs = (vec3_t*)SafeMalloc(numverts*sizeof(vec3_t), "NewGen"); + grouptris = (triangle_t*)SafeMalloc(numtris*sizeof(triangle_t), "NewGen"); + + for (count = 0; count < fmheader.num_tris; count++) + { + if (triangles[count].group == i) + { + fprintf(grpfile,"Triangle %d\n", count); + } + } + fprintf(grpfile,"\n"); + + + + + GetOneGroup(triangles, i, grouptris); + + num = 0; + for (j = 0; j < numtris; j++) + { + VectorCopy(grouptris[j].verts[0], v0); + VectorCopy(grouptris[j].verts[1], v1); + VectorCopy(grouptris[j].verts[2], v2); + VectorSubtract(v1, v0, diffvect1); + VectorSubtract(v2, v1, diffvect2); + CrossProduct( diffvect1, diffvect2, crossvect); + VectorAdd(aveNorm, crossvect, aveNorm); + VectorCopy(v0,vertices[num]); + num++; // FIXME + VectorCopy(v1,vertices[num]); + num++; // add routine to add only verts that + VectorCopy(v2,vertices[num]); + num++; // have not already been added + } + + assert (num >= 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 <linetype> %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<verts; i++) + { + u[i] *= scale; + v[i] *= scale; + } + return; +} + + +void GetOneGroup(trigroup_t *tris, int grp, triangle_t* triangles) +{ + int i; + int j; + + j = 0; + for (i = 0; i < fmheader.num_tris; i++) + { + if (tris[i].group == grp) + { + triangles[j++] = tris[i].triangle; + } + } + return; +} + + +int GetNumTris( trigroup_t *tris, int grp) +{ + int i; + int verts; + + verts = 0; + for (i = 0; i < fmheader.num_tris; i++) + { + if (tris[i].group == grp) + { + verts++; + } + } + return verts; +} + + +int ShareVertex( trigroup_t trione, trigroup_t tritwo) +{ + int i; + int j; + + i = 1; + j = 1; + for ( i = 0; i < 3; i++) + { + for ( j = 0; j < 3; j++) + { + if (DistBetween(trione.triangle.verts[i],tritwo.triangle.verts[j]) < TRIVERT_DIST) + { + return true; + } + } + } + return false; +} + + +float DistBetween(vec3_t point1, vec3_t point2) +{ + float dist; + + dist = (point1[0] - point2[0]); + dist *= dist; + dist += (point1[1] - point2[1])*(point1[1]-point2[1]); + dist += (point1[2] - point2[2])*(point1[2]-point2[2]); + dist = sqrt(dist); + return dist; +} + + +void GenSkin(char *ModelFile, char *OutputName, int Width, int Height) +{ + triangle_t *ptri; + mesh_node_t *pmnodes; + int i; + + pmnodes = NULL; + ptri = NULL; + + LoadTriangleList (ModelFile, &ptri, &fmheader.num_tris, &pmnodes, &fmheader.num_mesh_nodes); + if (g_ignoreTriUV) + { + for (i=0;i<fmheader.num_tris;i++) + { + ptri[i].HasUV=0; + } + } + + memset(pic,0,sizeof(pic)); + memset(pic_palette,0,sizeof(pic_palette)); + pic_palette[767] = pic_palette[766] = pic_palette[765] = 255; + + ScaleWidth = Width; + ScaleHeight = Height; + + BuildST (ptri, fmheader.num_tris, true); + + WritePCXfile (OutputName, pic, SKINPAGE_WIDTH, SKINPAGE_HEIGHT, pic_palette); + + printf("Gen Skin Stats:\n"); + printf(" Input Base: %s\n",ModelFile); + printf(" Input Dimensions: %d,%d\n",Width,Height); + printf("\n"); + printf(" Output File: %s\n",OutputName); + printf(" Output Dimensions: %d,%d\n",ScaleWidth,ScaleHeight); + + if (fmheader.num_mesh_nodes) + { + printf("\nNodes:\n"); + for(i=0;i<fmheader.num_mesh_nodes;i++) + { + printf(" %s\n",pmnodes[i].name); + } + } + + free(ptri); + free(pmnodes); +} + + +void Cmd_FMBeginGroup (void) +{ + GetScriptToken (false); + + g_no_opimizations = false; + + groups[num_groups].start_frame = fmheader.num_frames; + groups[num_groups].num_frames = 0; + + groups[num_groups].degrees = atol(token); + if (groups[num_groups].degrees < 1 || groups[num_groups].degrees > 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/images.c b/tools/quake2/qdata_heretic2/images.c index bdc8ba50..c2dc29fb 100644 --- a/tools/quake2/qdata_heretic2/images.c +++ b/tools/quake2/qdata_heretic2/images.c @@ -1,1397 +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 <windows.h> -#endif - -#include <GL/gl.h> - -#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<c ; i++) - if (pixels[i] == 0) - pixels[i] = alt_zero; -} - -#endif - - -// ******************************************************************** -// ** Mip Map Pre-Processing Routines -// ******************************************************************** - -#define intensity_value 1 - -static unsigned image_pal[256]; - -#define MAX_LAST 25 - -long palette_r[256], palette_g[256], palette_b[256]; -long last_r[MAX_LAST],last_g[MAX_LAST],last_b[MAX_LAST], last_i[MAX_LAST], last_place; - -long cached; - -void PrepareConvert(unsigned *palette) -{ - int i; - - for(i=0;i<256;i++) - { - palette_r[i] = (palette[i] & 0x00ff0000) >> 16; - palette_g[i] = (palette[i] & 0x0000ff00) >> 8; - palette_b[i] = (palette[i] & 0x000000ff); - } - - for(i=0;i<MAX_LAST;i++) - last_r[i] = -1; - - last_place = -1; -} - -int ConvertTrueColorToPal(unsigned r, unsigned g, unsigned b) -{ - int i; - long min_dist; - int min_index; - long dist; - long dr, dg, db, biggest_delta; - - for(i=0;i<MAX_LAST;i++) - if (r == last_r[i] && g == last_g[i] && b == last_b[i]) - { - cached++; - return last_i[i]; - } - - min_dist = 256 * 256 + 256 * 256 + 256 * 256; - biggest_delta = 256*256; - min_index = 0; - - for (i=0;i<256;i++) - { - dr = abs(palette_r[i] - r); - if (dr > 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<outwidth ; i++) - { - p1[i] = frac>>16; - frac += fracstep; - } - frac = 3*(fracstep>>2); - for (i=0 ; i<outwidth ; i++) - { - p2[i] = frac>>16; - frac += fracstep; - } - - cached = 0; - - for (i=0 ; i<outheight ; i++)//, out += outwidth) - { - inrow = in + inwidth*(int)((i+0.25)*inheight/outheight); - inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight); - - p1p = p1; - p2p = p2; - for (j=0 ; j<outwidth ; j++) - { - c1 = &palette[*((byte *)inrow + (*p1p))]; - c2 = &palette[*((byte *)inrow + (*p2p))]; - c3 = &palette[*((byte *)inrow2 + (*p1p++))]; - c4 = &palette[*((byte *)inrow2 + (*p2p++))]; - - 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); - } - } -} - -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<outwidth ; i++) - { - p1[i] = 4*(frac>>16); - frac += fracstep; - } - frac = 3*(fracstep>>2); - for (i=0 ; i<outwidth ; i++) - { - p2[i] = 4*(frac>>16); - frac += fracstep; - } - - for (i=0 ; i<outheight ; i++, out += outwidth) - { - inrow = in + inwidth*(int)((i+0.25)*inheight/outheight); - inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight); - frac = fracstep >> 1; - for (j=0 ; j<outwidth ; j++) - { - pix1 = (byte *)inrow + p1[j]; - pix2 = (byte *)inrow + p2[j]; - pix3 = (byte *)inrow2 + p1[j]; - pix4 = (byte *)inrow2 + p2[j]; - ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>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<height ; i++, in+=width) - { - for (j=0 ; j<width ; j+=8, out+=4, in+=8) - { - out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>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 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, w, h, lbmpalette); - - free (cropped); -} - -/* -============== -Cmd_Raw - -$grab filename x y width height -============== -*/ -void Cmd_Raw (void) -{ - int xl,yl,w,h,y; - byte *cropped; - char savename[1024]; - char dest[1024]; - - GetScriptToken (false); - - sprintf (savename, "%s%s.lmp", gamedir, token); - - if (g_release) - { - sprintf (dest, "%s.lmp", 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_Raw"); - for (y=0 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - - SaveFile (savename, cropped, w*h); - - free (cropped); -} - -/* -============================================================================= - -COLORMAP GRABBING - -============================================================================= -*/ - -/* -=============== -BestColor -=============== -*/ -byte BestColor (int r, int g, int b, int start, int stop) -{ - int i; - int dr, dg, db; - int bestdistortion, distortion; - int bestcolor; - byte *pal; - -// -// let any color go to 0 as a last resort -// - bestdistortion = 256*256*4; - bestcolor = 0; - - pal = colormap_palette + start*3; - for (i=start ; i<= stop ; i++) - { - dr = r - (int)pal[0]; - dg = g - (int)pal[1]; - db = b - (int)pal[2]; - pal += 3; - distortion = dr*dr + dg*dg + db*db; - if (distortion < bestdistortion) - { - if (!distortion) - return i; // perfect match - - bestdistortion = distortion; - bestcolor = i; - } - } - - return bestcolor; -} - - -/* -============== -Cmd_Colormap - -$colormap filename - - the brightes colormap is first in the table (FIXME: reverse this now?) - - 64 rows of 256 : lightmaps - 256 rows of 256 : translucency table -============== -*/ -void Cmd_Colormap (void) -{ - int levels, brights; - int l, c; - float frac, red, green, blue; - float range; - byte *cropped, *lump_p; - char savename[1024]; - char dest[1024]; - - colormap_issued = true; - if (!g_release) - memcpy (colormap_palette, lbmpalette, 768); - - if (!ScriptTokenAvailable ()) - { // just setting colormap_issued - return; - } - - GetScriptToken (false); - sprintf (savename, "%spics/%s.pcx", gamedir, token); - - if (g_release) - { - sprintf (dest, "pics/%s.pcx", token); - ReleaseFile (dest); - return; - } - - range = 2; - levels = 64; - brights = 1; // ignore 255 (transparent) - - cropped = (byte *) SafeMalloc((levels+256)*256, "Cmd_ColorMap"); - lump_p = cropped; - -// shaded levels - for (l=0;l<levels;l++) - { - frac = range - range*(float)l/(levels-1); - for (c=0 ; c<256-brights ; c++) - { - red = lbmpalette[c*3]; - green = lbmpalette[c*3+1]; - blue = lbmpalette[c*3+2]; - - red = (int)(red*frac+0.5); - green = (int)(green*frac+0.5); - blue = (int)(blue*frac+0.5); - -// -// note: 254 instead of 255 because 255 is the transparent color, and we -// don't want anything remapping to that -// don't use color 0, because NT can't remap that (or 255) -// - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - - // fullbrights allways stay the same - for ( ; c<256 ; c++) - *lump_p++ = c; - } - -// 66% transparancy table - for (l=0;l<255;l++) - { - for (c=0 ; c<255 ; c++) - { - red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; - green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; - blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; - - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - *lump_p++ = 255; - } - for (c=0 ; c<256 ; c++) - *lump_p++ = 255; - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); - - free (cropped); -} - -/* -============================================================================= - -MIPTEX GRABBING - -============================================================================= -*/ - -byte pixdata[256]; - -int d_red, d_green, d_blue; - -byte palmap[32][32][32]; -qboolean palmap_built; - -/* -============= -FindColor -============= -*/ -int FindColor (int r, int g, int b) -{ - int bestcolor; - - if (r > 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<count ; i++) - { - pix = pixdata[i]; - - r += lbmpalette[pix*3]; - g += lbmpalette[pix*3+1]; - b += lbmpalette[pix*3+2]; - vis++; - } - - r /= vis; - g /= vis; - b /= vis; - - // error diffusion - r += d_red; - g += d_green; - b += d_blue; - -// -// find the best color -// - bestcolor = FindColor (r, g, b); - - // error diffusion - pal = colormap_palette + bestcolor*3; - d_red = r - (int)pal[0]; - d_green = g - (int)pal[1]; - d_blue = b - (int)pal[2]; - - return bestcolor; -} - - -typedef enum -{ - pt_contents, - pt_flags, - pt_animvalue, - pt_altnamevalue, - pt_damagenamevalue, - pt_flagvalue, - pt_materialvalue, - pt_scale, - pt_mip, - pt_detail, - pt_gl, - pt_nomip, - pt_detailer, -} parmtype_t; - -typedef struct -{ - char *name; - int flags; - parmtype_t type; -} mipparm_t; - -mipparm_t mipparms[] = -{ - // utility content attributes - {"pushpull",CONTENTS_PUSHPULL, pt_contents}, - {"water", CONTENTS_WATER, pt_contents}, - {"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging - {"lava", CONTENTS_LAVA, pt_contents}, // very damaging - {"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures - {"mist", CONTENTS_MIST, pt_contents}, // non-solid window - {"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes - {"playerclip", CONTENTS_PLAYERCLIP, pt_contents}, - {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents}, - - // utility surface attributes - {"hint", SURF_HINT, pt_flags}, - {"skip", SURF_SKIP, pt_flags}, - {"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity - - {"animspeed",SURF_ANIMSPEED, pt_flagvalue}, // value will hold the anim speed in fps - - // texture chaining - {"anim", 0, pt_animvalue}, // animname is the next animation - {"alt", 0, pt_altnamevalue}, // altname is the alternate texture - {"damage", 0, pt_damagenamevalue}, // damagename is the damage texture - {"scale", 0, pt_scale}, // next two values are for scale - {"mip", 0, pt_mip}, - {"detail", 0, pt_detail}, - - {"GL_ZERO", GL_ZERO, pt_gl}, - {"GL_ONE", GL_ONE, pt_gl}, - {"GL_SRC_COLOR", GL_SRC_COLOR, pt_gl}, - {"GL_ONE_MINUS_SRC_COLOR", GL_ONE_MINUS_SRC_COLOR, pt_gl}, - {"GL_DST_COLOR", GL_DST_COLOR, pt_gl}, - {"GL_ONE_MINUS_DST_COLOR", GL_ONE_MINUS_DST_COLOR, pt_gl}, - {"GL_SRC_ALPHA", GL_SRC_ALPHA, pt_gl}, - {"GL_ONE_MINUS_SRC_ALPHA", GL_ONE_MINUS_SRC_ALPHA, pt_gl}, - {"GL_DST_ALPHA", GL_DST_ALPHA, pt_gl}, - {"GL_ONE_MINUS_DST_ALPHA", GL_ONE_MINUS_DST_ALPHA, pt_gl}, - {"GL_SRC_ALPHA_SATURATE", GL_SRC_ALPHA_SATURATE, pt_gl}, - - // server attributes - {"slick", SURF_SLICK, pt_flags}, - - // drawing attributes - {"sky", SURF_SKY, pt_flags}, - {"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures - {"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright - {"trans66", SURF_TRANS66, pt_flags}, - {"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0 - {"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures - {"alpha", SURF_ALPHA_TEXTURE, pt_flags}, - {"undulate", SURF_UNDULATE, pt_flags}, // rock surface up and down... - {"skyreflect", SURF_SKYREFLECT, pt_flags}, // liquid will somewhat reflect the sky - not quite finished.... - - {"material", SURF_MATERIAL, pt_materialvalue}, - {"metal", SURF_TYPE_METAL, pt_flags}, - {"stone", SURF_TYPE_STONE, pt_flags}, - {"wood", SURF_TYPE_WOOD, pt_flags}, - - {"m_nomip", 0, pt_nomip}, - {"m_detail", 0, pt_detailer}, - - {NULL, 0, pt_contents} -}; - -/* -============== -Cmd_Mip - -$mip filename x y width height <OPTIONS> -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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *destl++ = *sourcel++; // RGBA - } - sourcel += linedelta; - } - - qtex32 = CreateMip32(bufferl, w, h, &size, true); - - qtex32->flags |= 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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *dest++ = *source++; - } - source += linedelta; - } - - qtex = CreateMip(buffer, w, h, lbmpalette, &size, true); - - 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); - - // - // 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); - } -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> +#endif + +#include <GL/gl.h> + +#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<c ; i++) + if (pixels[i] == 0) + pixels[i] = alt_zero; +} + +#endif + + +// ******************************************************************** +// ** Mip Map Pre-Processing Routines +// ******************************************************************** + +#define intensity_value 1 + +static unsigned image_pal[256]; + +#define MAX_LAST 25 + +long palette_r[256], palette_g[256], palette_b[256]; +long last_r[MAX_LAST],last_g[MAX_LAST],last_b[MAX_LAST], last_i[MAX_LAST], last_place; + +long cached; + +void PrepareConvert(unsigned *palette) +{ + int i; + + for(i=0;i<256;i++) + { + palette_r[i] = (palette[i] & 0x00ff0000) >> 16; + palette_g[i] = (palette[i] & 0x0000ff00) >> 8; + palette_b[i] = (palette[i] & 0x000000ff); + } + + for(i=0;i<MAX_LAST;i++) + last_r[i] = -1; + + last_place = -1; +} + +int ConvertTrueColorToPal(unsigned r, unsigned g, unsigned b) +{ + int i; + long min_dist; + int min_index; + long dist; + long dr, dg, db, biggest_delta; + + for(i=0;i<MAX_LAST;i++) + if (r == last_r[i] && g == last_g[i] && b == last_b[i]) + { + cached++; + return last_i[i]; + } + + min_dist = 256 * 256 + 256 * 256 + 256 * 256; + biggest_delta = 256*256; + min_index = 0; + + for (i=0;i<256;i++) + { + dr = abs(palette_r[i] - r); + if (dr > 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<outwidth ; i++) + { + p1[i] = frac>>16; + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i<outwidth ; i++) + { + p2[i] = frac>>16; + frac += fracstep; + } + + cached = 0; + + for (i=0 ; i<outheight ; i++)//, out += outwidth) + { + inrow = in + inwidth*(int)((i+0.25)*inheight/outheight); + inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight); + + p1p = p1; + p2p = p2; + for (j=0 ; j<outwidth ; j++) + { + c1 = &palette[*((byte *)inrow + (*p1p))]; + c2 = &palette[*((byte *)inrow + (*p2p))]; + c3 = &palette[*((byte *)inrow2 + (*p1p++))]; + c4 = &palette[*((byte *)inrow2 + (*p2p++))]; + + 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); + } + } +} + +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<outwidth ; i++) + { + p1[i] = 4*(frac>>16); + frac += fracstep; + } + frac = 3*(fracstep>>2); + for (i=0 ; i<outwidth ; i++) + { + p2[i] = 4*(frac>>16); + frac += fracstep; + } + + for (i=0 ; i<outheight ; i++, out += outwidth) + { + inrow = in + inwidth*(int)((i+0.25)*inheight/outheight); + inrow2 = in + inwidth*(int)((i+0.75)*inheight/outheight); + frac = fracstep >> 1; + for (j=0 ; j<outwidth ; j++) + { + pix1 = (byte *)inrow + p1[j]; + pix2 = (byte *)inrow + p2[j]; + pix3 = (byte *)inrow2 + p1[j]; + pix4 = (byte *)inrow2 + p2[j]; + ((byte *)(out+j))[0] = (pix1[0] + pix2[0] + pix3[0] + pix4[0])>>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<height ; i++, in+=width) + { + for (j=0 ; j<width ; j+=8, out+=4, in+=8) + { + out[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>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 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, w, h, lbmpalette); + + free (cropped); +} + +/* +============== +Cmd_Raw + +$grab filename x y width height +============== +*/ +void Cmd_Raw (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetScriptToken (false); + + sprintf (savename, "%s%s.lmp", gamedir, token); + + if (g_release) + { + sprintf (dest, "%s.lmp", 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_Raw"); + for (y=0 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + + SaveFile (savename, cropped, w*h); + + free (cropped); +} + +/* +============================================================================= + +COLORMAP GRABBING + +============================================================================= +*/ + +/* +=============== +BestColor +=============== +*/ +byte BestColor (int r, int g, int b, int start, int stop) +{ + int i; + int dr, dg, db; + int bestdistortion, distortion; + int bestcolor; + byte *pal; + +// +// let any color go to 0 as a last resort +// + bestdistortion = 256*256*4; + bestcolor = 0; + + pal = colormap_palette + start*3; + for (i=start ; i<= stop ; i++) + { + dr = r - (int)pal[0]; + dg = g - (int)pal[1]; + db = b - (int)pal[2]; + pal += 3; + distortion = dr*dr + dg*dg + db*db; + if (distortion < bestdistortion) + { + if (!distortion) + return i; // perfect match + + bestdistortion = distortion; + bestcolor = i; + } + } + + return bestcolor; +} + + +/* +============== +Cmd_Colormap + +$colormap filename + + the brightes colormap is first in the table (FIXME: reverse this now?) + + 64 rows of 256 : lightmaps + 256 rows of 256 : translucency table +============== +*/ +void Cmd_Colormap (void) +{ + int levels, brights; + int l, c; + float frac, red, green, blue; + float range; + byte *cropped, *lump_p; + char savename[1024]; + char dest[1024]; + + colormap_issued = true; + if (!g_release) + memcpy (colormap_palette, lbmpalette, 768); + + if (!ScriptTokenAvailable ()) + { // just setting colormap_issued + return; + } + + GetScriptToken (false); + sprintf (savename, "%spics/%s.pcx", gamedir, token); + + if (g_release) + { + sprintf (dest, "pics/%s.pcx", token); + ReleaseFile (dest); + return; + } + + range = 2; + levels = 64; + brights = 1; // ignore 255 (transparent) + + cropped = (byte *) SafeMalloc((levels+256)*256, "Cmd_ColorMap"); + lump_p = cropped; + +// shaded levels + for (l=0;l<levels;l++) + { + frac = range - range*(float)l/(levels-1); + for (c=0 ; c<256-brights ; c++) + { + red = lbmpalette[c*3]; + green = lbmpalette[c*3+1]; + blue = lbmpalette[c*3+2]; + + red = (int)(red*frac+0.5); + green = (int)(green*frac+0.5); + blue = (int)(blue*frac+0.5); + +// +// note: 254 instead of 255 because 255 is the transparent color, and we +// don't want anything remapping to that +// don't use color 0, because NT can't remap that (or 255) +// + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + + // fullbrights allways stay the same + for ( ; c<256 ; c++) + *lump_p++ = c; + } + +// 66% transparancy table + for (l=0;l<255;l++) + { + for (c=0 ; c<255 ; c++) + { + red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; + green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; + blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; + + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + *lump_p++ = 255; + } + for (c=0 ; c<256 ; c++) + *lump_p++ = 255; + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); + + free (cropped); +} + +/* +============================================================================= + +MIPTEX GRABBING + +============================================================================= +*/ + +byte pixdata[256]; + +int d_red, d_green, d_blue; + +byte palmap[32][32][32]; +qboolean palmap_built; + +/* +============= +FindColor +============= +*/ +int FindColor (int r, int g, int b) +{ + int bestcolor; + + if (r > 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<count ; i++) + { + pix = pixdata[i]; + + r += lbmpalette[pix*3]; + g += lbmpalette[pix*3+1]; + b += lbmpalette[pix*3+2]; + vis++; + } + + r /= vis; + g /= vis; + b /= vis; + + // error diffusion + r += d_red; + g += d_green; + b += d_blue; + +// +// find the best color +// + bestcolor = FindColor (r, g, b); + + // error diffusion + pal = colormap_palette + bestcolor*3; + d_red = r - (int)pal[0]; + d_green = g - (int)pal[1]; + d_blue = b - (int)pal[2]; + + return bestcolor; +} + + +typedef enum +{ + pt_contents, + pt_flags, + pt_animvalue, + pt_altnamevalue, + pt_damagenamevalue, + pt_flagvalue, + pt_materialvalue, + pt_scale, + pt_mip, + pt_detail, + pt_gl, + pt_nomip, + pt_detailer, +} parmtype_t; + +typedef struct +{ + char *name; + int flags; + parmtype_t type; +} mipparm_t; + +mipparm_t mipparms[] = +{ + // utility content attributes + {"pushpull",CONTENTS_PUSHPULL, pt_contents}, + {"water", CONTENTS_WATER, pt_contents}, + {"slime", CONTENTS_SLIME, pt_contents}, // mildly damaging + {"lava", CONTENTS_LAVA, pt_contents}, // very damaging + {"window", CONTENTS_WINDOW, pt_contents}, // solid, but doesn't eat internal textures + {"mist", CONTENTS_MIST, pt_contents}, // non-solid window + {"origin", CONTENTS_ORIGIN, pt_contents}, // center of rotating brushes + {"playerclip", CONTENTS_PLAYERCLIP, pt_contents}, + {"monsterclip", CONTENTS_MONSTERCLIP, pt_contents}, + + // utility surface attributes + {"hint", SURF_HINT, pt_flags}, + {"skip", SURF_SKIP, pt_flags}, + {"light", SURF_LIGHT, pt_flagvalue}, // value is the light quantity + + {"animspeed",SURF_ANIMSPEED, pt_flagvalue}, // value will hold the anim speed in fps + + // texture chaining + {"anim", 0, pt_animvalue}, // animname is the next animation + {"alt", 0, pt_altnamevalue}, // altname is the alternate texture + {"damage", 0, pt_damagenamevalue}, // damagename is the damage texture + {"scale", 0, pt_scale}, // next two values are for scale + {"mip", 0, pt_mip}, + {"detail", 0, pt_detail}, + + {"GL_ZERO", GL_ZERO, pt_gl}, + {"GL_ONE", GL_ONE, pt_gl}, + {"GL_SRC_COLOR", GL_SRC_COLOR, pt_gl}, + {"GL_ONE_MINUS_SRC_COLOR", GL_ONE_MINUS_SRC_COLOR, pt_gl}, + {"GL_DST_COLOR", GL_DST_COLOR, pt_gl}, + {"GL_ONE_MINUS_DST_COLOR", GL_ONE_MINUS_DST_COLOR, pt_gl}, + {"GL_SRC_ALPHA", GL_SRC_ALPHA, pt_gl}, + {"GL_ONE_MINUS_SRC_ALPHA", GL_ONE_MINUS_SRC_ALPHA, pt_gl}, + {"GL_DST_ALPHA", GL_DST_ALPHA, pt_gl}, + {"GL_ONE_MINUS_DST_ALPHA", GL_ONE_MINUS_DST_ALPHA, pt_gl}, + {"GL_SRC_ALPHA_SATURATE", GL_SRC_ALPHA_SATURATE, pt_gl}, + + // server attributes + {"slick", SURF_SLICK, pt_flags}, + + // drawing attributes + {"sky", SURF_SKY, pt_flags}, + {"warping", SURF_WARP, pt_flags}, // only valid with 64x64 textures + {"trans33", SURF_TRANS33, pt_flags}, // translucent should allso set fullbright + {"trans66", SURF_TRANS66, pt_flags}, + {"flowing", SURF_FLOWING, pt_flags}, // flow direction towards angle 0 + {"nodraw", SURF_NODRAW, pt_flags}, // for clip textures and trigger textures + {"alpha", SURF_ALPHA_TEXTURE, pt_flags}, + {"undulate", SURF_UNDULATE, pt_flags}, // rock surface up and down... + {"skyreflect", SURF_SKYREFLECT, pt_flags}, // liquid will somewhat reflect the sky - not quite finished.... + + {"material", SURF_MATERIAL, pt_materialvalue}, + {"metal", SURF_TYPE_METAL, pt_flags}, + {"stone", SURF_TYPE_STONE, pt_flags}, + {"wood", SURF_TYPE_WOOD, pt_flags}, + + {"m_nomip", 0, pt_nomip}, + {"m_detail", 0, pt_detailer}, + + {NULL, 0, pt_contents} +}; + +/* +============== +Cmd_Mip + +$mip filename x y width height <OPTIONS> +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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *destl++ = *sourcel++; // RGBA + } + sourcel += linedelta; + } + + qtex32 = CreateMip32(bufferl, w, h, &size, true); + + qtex32->flags |= 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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + qtex = CreateMip(buffer, w, h, lbmpalette, &size, true); + + 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); + + // + // 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 index 09b963f6..af458ba2 100644 --- a/tools/quake2/qdata_heretic2/jointed.c +++ b/tools/quake2/qdata_heretic2/jointed.c @@ -1,572 +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 <assert.h> -#include <math.h> -#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); - } -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> +#include <math.h> +#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 index 6907a2d8..ffd82631 100644 --- a/tools/quake2/qdata_heretic2/jointed.h +++ b/tools/quake2/qdata_heretic2/jointed.h @@ -1,35 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e489114e..046bebdf 100644 --- a/tools/quake2/qdata_heretic2/joints.h +++ b/tools/quake2/qdata_heretic2/joints.h @@ -1,144 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index d594cafe..5ae30a15 100644 --- a/tools/quake2/qdata_heretic2/models.c +++ b/tools/quake2/qdata_heretic2/models.c @@ -1,2050 +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 <assert.h> -#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 ; i<sizeof(dmdl_t)/4 ; i++) - ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); - - SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); - - // - // write out the skin names - // - SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); - - // - // write out the texture coordinates - // - c_on = c_off = 0; - for (i=0 ; i<model.num_st ; i++) - { - base_st[i].s = LittleShort (base_st[i].s); - base_st[i].t = LittleShort (base_st[i].t); - } - - SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); - - // - // write out the triangles - // - for (i=0 ; i<model.num_tris ; i++) - { - int j; - dtriangle_t tri; - - for (j=0 ; j<3 ; j++) - { - tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); - tri.index_st[j] = LittleShort (triangles[i].index_st[j]); - } - - SafeWrite (modelouthandle, &tri, sizeof(tri)); - } - - // - // write out the frames - // - for (i=0 ; i<model.num_frames ; i++) - { - in = &g_frames[i]; - out = (daliasframe_t *)buffer; - - strcpy (out->name, 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 ; j<model.num_xyz ; j++) - { - // all of these are byte values, so no need to deal with endianness - out->verts[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 ; i<model.num_frames ; i++) - { - in = &g_frames[i]; - - for (j = 0 ; j < new_num_verts[0]; ++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] ); - - // 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 ; i<sizeof(dmdl_t)/4 ; i++) - ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); - - SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); - - // - // write out the skin names - // - SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); - - // - // write out the texture coordinates - // - c_on = c_off = 0; - for (i=0 ; i<model.num_st ; i++) - { - base_st[i].s = LittleShort (base_st[i].s); - base_st[i].t = LittleShort (base_st[i].t); - } - - SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); - - // - // write out the triangles - // - for (i=0 ; i<model.num_tris ; i++) - { - int j; - dtriangle_t tri; - - for (j=0 ; j<3 ; j++) - { - tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); - tri.index_st[j] = LittleShort (triangles[i].index_st[j]); - } - - SafeWrite (modelouthandle, &tri, sizeof(tri)); - } - - // - // write out the frames - // - for (i=0 ; i<model.num_frames ; i++) - { - in = &g_frames[i]; - out = (daliasframe_t *)buffer; - - strcpy (out->name, 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 ; j<model.num_xyz ; j++) - { - // all of these are byte values, so no need to deal with endianness - out->verts[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 ; i<model.num_skins ; i++) - { - ReleaseFile (g_skins[i]); - } - model.num_frames = 0; - return; - } - -// -// write the model output file -// - if (modelname[0]) - sprintf (name, "%s%s", g_outputDir, modelname); - else - sprintf (name, "%s/tris.md2", g_outputDir); - printf ("saving to %s\n", name); - CreatePath (name); - modelouthandle = SafeOpenWrite (name); - -#if 1 - if(jointed != NOT_JOINTED) - WriteJointedModelFile(modelouthandle); - else -#endif - WriteModelFile(modelouthandle); - - printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight); - printf ("First frame boundaries:\n"); - printf (" minimum x: %3f\n", g_frames[0].mins[0]); - printf (" maximum x: %3f\n", g_frames[0].maxs[0]); - printf (" minimum y: %3f\n", g_frames[0].mins[1]); - printf (" maximum y: %3f\n", g_frames[0].maxs[1]); - printf (" minimum z: %3f\n", g_frames[0].mins[2]); - printf (" maximum z: %3f\n", g_frames[0].maxs[2]); - printf ("%4d vertices\n", model.num_xyz); - printf ("%4d triangles\n", model.num_tris); - printf ("%4d frame\n", model.num_frames); - printf ("%4d glverts\n", numglverts); - printf ("%4d glcmd\n", model.num_glcmds); - printf ("%4d skins\n", model.num_skins); - printf ("file size: %d\n", (int)ftell (modelouthandle) ); - printf ("---------------------\n"); - - 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); - - fclose (headerouthandle); - headerouthandle = NULL; -} - - -/* -================================================================= - -ALIAS MODEL DISPLAY LIST GENERATION - -================================================================= -*/ - -int strip_xyz[128]; -int strip_st[128]; -int strip_tris[128]; -int stripcount; - -/* -================ -StripLength -================ -*/ -static int StripLength (int starttri, int startv) -{ - int m1, m2; - int st1, st2; - int j; - dtriangle_t *last, *check; - int k; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) - { - 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]) - 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 ; j<model.num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - -/* -=========== -FanLength -=========== -*/ -static int FanLength (int starttri, int startv) -{ - int m1, m2; - int st1, st2; - int j; - dtriangle_t *last, *check; - int k; - - used[starttri] = 2; - - last = &triangles[starttri]; - - strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) - { - 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]) - 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<model.num_tris ; j++) - if (used[j] == 2) - used[j] = 0; - - return stripcount; -} - - - -/* -================ -BuildGlCmds - -Generate a list of trifans or strips -for the model, which holds for all frames -================ -*/ -static void BuildGlCmds (void) -{ - int i, j, k; - int startv; - float s, t; - int len, bestlen, besttype; - int best_xyz[1024]; - int best_st[1024]; - int best_tris[1024]; - int type; - - // - // build tristrips - // - numcommands = 0; - numglverts = 0; - memset (used, 0, sizeof(used)); - for (i=0 ; i<model.num_tris ; i++) - { - // pick an unused triangle and start the trifan - if (used[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); - else - len = FanLength (i, startv); - if (len > bestlen) - { - besttype = type; - bestlen = len; - for (j=0 ; j<bestlen+2 ; j++) - { - best_st[j] = strip_st[j]; - best_xyz[j] = strip_xyz[j]; - } - for (j=0 ; j<bestlen ; j++) - best_tris[j] = strip_tris[j]; - } - } - } - - // mark the tris on the best strip/fan as used - for (j=0 ; j<bestlen ; j++) - used[best_tris[j]] = 1; - - if (besttype == 1) - commands[numcommands++] = (bestlen+2); - else - commands[numcommands++] = -(bestlen+2); - - numglverts += bestlen+2; - - for (j=0 ; j<bestlen+2 ; j++) - { - // emit a vertex into the reorder buffer - k = best_st[j]; - - // emit s/t coords into the commands stream - s = base_st[k].s; - t = base_st[k].t; - - s = (s + 0.5) / model.skinwidth; - t = (t + 0.5) / model.skinheight; - - *(float *)&commands[numcommands++] = s; - *(float *)&commands[numcommands++] = t; - *(int *)&commands[numcommands++] = best_xyz[j]; - } - } - - commands[numcommands++] = 0; // end of list marker -} - - -/* -=============================================================== - -BASE FRAME SETUP - -=============================================================== -*/ - -/* -============ -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 -============ -*/ -#if 0 -static void OldBuildST (triangle_t *ptri, int numtri) -{ - int i, j; - int width, height, iwidth, iheight, swidth; - float basex, basey; - float s_scale, t_scale; - float scale; - vec3_t mins, maxs; - float *pbasevert; - vec3_t vtemp1, vtemp2, normal; - - // - // find bounds of all the verts on the base frame - // - ClearBounds (mins, maxs); - - for (i=0 ; i<numtri ; i++) - for (j=0 ; j<3 ; j++) - AddPointToBounds (ptri[i].verts[j], mins, maxs); - - for (i=0 ; i<3 ; i++) - { - mins[i] = floor(mins[i]); - maxs[i] = ceil(maxs[i]); - } - - width = maxs[0] - mins[0]; - height = maxs[2] - mins[2]; - - 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<numtri ; i++) - { - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - if (normal[1] > 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<numtri ; i++) - for (j=0 ; j<3 ; j++) - AddPointToBounds (ptri[i].verts[j], mins, maxs); - - for (i=0 ; i<3 ; i++) - { - mins[i] = floor(mins[i]); - maxs[i] = ceil(maxs[i]); - } - - width = maxs[0] - mins[0]; - height = maxs[2] - mins[2]; - - - scWidth = (ScaleWidth/2)*SCALE_ADJUST_FACTOR; - 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) - 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<numtri ; i++) - { - if (ptri[i].HasUV) - { - for (j=0 ; j<3 ; j++) - { - triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*iwidth); - triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*iheight); - } - } - else - { - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - if (normal[1] > 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<model.num_tris ; i++) - { - for (j=0 ; j<3 ; j++) - { - // get the xyz index - for (k=0 ; k<model.num_xyz ; k++) - if (VectorCompare (ptri[i].verts[j], base_xyz[k])) - break; // this vertex is already in the base vertex list - - if (k == model.num_xyz) - { // new index - VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]); - - if(clustered) - ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&clusters, (IntListNode_t **)&vertLists, (int *)&num_verts, (int *)&new_num_verts); - - model.num_xyz++; - } - - triangles[i].index_xyz[j] = k; - - // get the st index - for (k=0 ; k<model.num_st ; k++) - if (triangle_st[i][j][0] == base_st[k].s - && triangle_st[i][j][1] == base_st[k].t) - break; // this vertex is already in the base vertex list - - if (k == model.num_st) - { // new index - base_st[model.num_st].s = triangle_st[i][j][0]; - base_st[model.num_st].t = triangle_st[i][j][1]; - model.num_st++; - } - - triangles[i].index_st[j] = k; - } - } - - // build triangle strips / fans - BuildGlCmds (); -} - -//=============================================================== - -char *FindFrameFile (char *frame) -{ - int time1; - char file1[1024]; - static char retname[1024]; - char base[32]; - char suffix[32]; - 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; - - 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 ; i<model.num_xyz ; i++) - { - vnorms[i].numnormals = 0; - VectorClear (vnorms[i].normalsum); - } - ClearBounds (fr->mins, 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 ; i<num_tris ; i++) - { - vec3_t vtemp1, vtemp2, normal; - float ftemp; - - VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); - VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); - CrossProduct (vtemp1, vtemp2, normal); - - VectorNormalize (normal, normal); - - // rotate the normal so the model faces down the positive x axis - ftemp = normal[0]; - normal[0] = -normal[1]; - normal[1] = ftemp; - - for (j=0 ; j<3 ; j++) - { - index_xyz = triangles[i].index_xyz[j]; - - // rotate the vertices so the model faces down the positive x axis - // also adjust the vertices to the desired origin - ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + - adjust[0]; - ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + - adjust[1]; - ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + - adjust[2]; - - AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<model.num_xyz ; i++) - { - int j; - vec3_t v; - float maxdot; - int maxdotindex; - int c; - - c = vnorms[i].numnormals; - if (!c) - Error ("Vertex with no triangles attached"); - - VectorScale (vnorms[i].normalsum, 1.0/c, v); - VectorNormalize (v, v); - - maxdot = -999999.0; - maxdotindex = -1; - - for (j=0 ; j<NUMVERTEXNORMALS ; j++) - { - float dot; - - dot = DotProduct (v, avertexnormals[j]); - if (dot > 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<model.skinheight ; y++) - { - memcpy (cropped+y*model.skinwidth, - pixels+y*width, model.skinwidth); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, model.skinwidth, - model.skinheight, palette); - - free (pixels); - free (palette); - free (cropped); -} - - -/* -================= -Cmd_Origin -================= -*/ -void Cmd_Origin (void) -{ - // rotate points into frame of reference so model points down the - // positive x axis - GetScriptToken (false); - adjust[1] = -atof (token); - - GetScriptToken (false); - adjust[0] = atof (token); - - GetScriptToken (false); - adjust[2] = -atof (token); -} - - -/* -================= -Cmd_ScaleUp -================= -*/ -void Cmd_ScaleUp (void) -{ - GetScriptToken (false); - scale_up = atof (token); - if (g_skipmodel || g_release || g_archive) - return; - - printf ("Scale up: %f\n", scale_up); -} - - -/* -================= -Cmd_Skinsize - -Set a skin size other than the default -================= -*/ -void Cmd_Skinsize (void) -{ - GetScriptToken (false); - g_fixedwidth = atoi(token); - GetScriptToken (false); - g_fixedheight = atoi(token); -} - -/* -================= -Cmd_Modelname - -Gives a different name/location for the file, instead of the cddir -================= -*/ -void Cmd_Modelname (void) -{ - GetScriptToken (false); - strcpy (modelname, token); -} - -/* -=============== -Cmd_Cd -=============== -*/ -void Cmd_Cd (void) -{ - char temp[256]; - - FinishModel (); - ClearModel (); - - GetScriptToken (false); - - // this is a silly mess... - sprintf (cdpartial, "models/%s", token); - sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); - sprintf (cddir, "%s%s", gamedir, cdpartial); - - // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too. - sprintf(temp, "%s%s", g_outputDir, cdpartial); - strcpy(g_outputDir, temp); - - // 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 monsters) - if (!g_only[0]) - return; - if (strncmp(token, g_only, strlen(g_only))) - { - g_skipmodel = true; - printf ("skipping %s\n", cdpartial); - } -} - -/* -================= -Cmd_Cluster -================= -*/ -void Cmd_Cluster() -{ - 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); - - LoadClusters(file1, (int **)&clusters, (int *)&num_verts, jointed); - - new_num_verts[0] = num_verts[0]; - - clustered = 1; -} - -// Model construction cover functions. -void MODELCMD_Modelname (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - Cmd_Modelname (); -/* - switch(modeltype) - { - case MODEL_MD2: - Cmd_Modelname (); - break; - case MODEL_FM: - Cmd_FMModelname (); - break; - } -*/ -} - -void MODELCMD_Cd (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Cd (); - break; - case MODEL_FM: - Cmd_FMCd (); - break; - } -} - -void MODELCMD_Origin (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - Cmd_Origin (); -/* switch(modeltype) - { - case MODEL_MD2: - Cmd_Origin (); - break; - case MODEL_FM: - Cmd_FMOrigin (); - break; - } -*/ -} - -void MODELCMD_Cluster (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Cluster (); - break; - case MODEL_FM: - Cmd_FMCluster (); - break; - } -} - -void MODELCMD_Base (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Base (); - break; - case MODEL_FM: - Cmd_FMBase (false); - break; - } -} - -void MODELCMD_BaseST (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Base (); - break; - case MODEL_FM: - Cmd_FMBase (true); - break; - } -} - -void MODELCMD_ScaleUp (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - Cmd_ScaleUp (); -/* switch(modeltype) - { - case MODEL_MD2: - Cmd_ScaleUp (); - break; - case MODEL_FM: - Cmd_FMScaleUp (); - break; - } -*/ -} - -void MODELCMD_Frame (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Frame (); - break; - case MODEL_FM: - Cmd_FMFrame (); - break; - } -} - -void MODELCMD_Skin (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - Cmd_Skin (); - break; - case MODEL_FM: - Cmd_FMSkin (); - break; - } -} - -void MODELCMD_Skinsize (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - Cmd_Skinsize (); -/* - switch(modeltype) - { - case MODEL_MD2: - Cmd_Skinsize (); - break; - case MODEL_FM: - Cmd_FMSkinsize (); - break; - } -*/ -} - -void MODELCMD_Skeleton (int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - break; - case MODEL_FM: - Cmd_FMSkeleton (); - break; - } -} - -void MODELCMD_BeginGroup(int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - break; - case MODEL_FM: - Cmd_FMBeginGroup(); - break; - } -} - -void MODELCMD_EndGroup(int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - break; - case MODEL_FM: - Cmd_FMEndGroup(); - break; - } -} - -void MODELCMD_Referenced(int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - break; - case MODEL_FM: - Cmd_FMReferenced(); - break; - } -} - -void MODELCMD_NodeOrder(int modeltype) -{ - if (g_forcemodel) - modeltype = g_forcemodel; - - switch(modeltype) - { - case MODEL_MD2: - break; - case MODEL_FM: - Cmd_FMNodeOrder(); - break; - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> +#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 ; i<sizeof(dmdl_t)/4 ; i++) + ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); + + SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); + + // + // write out the skin names + // + SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); + + // + // write out the texture coordinates + // + c_on = c_off = 0; + for (i=0 ; i<model.num_st ; i++) + { + base_st[i].s = LittleShort (base_st[i].s); + base_st[i].t = LittleShort (base_st[i].t); + } + + SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); + + // + // write out the triangles + // + for (i=0 ; i<model.num_tris ; i++) + { + int j; + dtriangle_t tri; + + for (j=0 ; j<3 ; j++) + { + tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); + tri.index_st[j] = LittleShort (triangles[i].index_st[j]); + } + + SafeWrite (modelouthandle, &tri, sizeof(tri)); + } + + // + // write out the frames + // + for (i=0 ; i<model.num_frames ; i++) + { + in = &g_frames[i]; + out = (daliasframe_t *)buffer; + + strcpy (out->name, 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 ; j<model.num_xyz ; j++) + { + // all of these are byte values, so no need to deal with endianness + out->verts[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 ; i<model.num_frames ; i++) + { + in = &g_frames[i]; + + for (j = 0 ; j < new_num_verts[0]; ++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] ); + + // 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 ; i<sizeof(dmdl_t)/4 ; i++) + ((int *)&modeltemp)[i] = LittleLong (((int *)&model)[i]); + + SafeWrite (modelouthandle, &modeltemp, sizeof(modeltemp)); + + // + // write out the skin names + // + SafeWrite (modelouthandle, g_skins, model.num_skins * MAX_SKINNAME); + + // + // write out the texture coordinates + // + c_on = c_off = 0; + for (i=0 ; i<model.num_st ; i++) + { + base_st[i].s = LittleShort (base_st[i].s); + base_st[i].t = LittleShort (base_st[i].t); + } + + SafeWrite (modelouthandle, base_st, model.num_st * sizeof(base_st[0])); + + // + // write out the triangles + // + for (i=0 ; i<model.num_tris ; i++) + { + int j; + dtriangle_t tri; + + for (j=0 ; j<3 ; j++) + { + tri.index_xyz[j] = LittleShort (triangles[i].index_xyz[j]); + tri.index_st[j] = LittleShort (triangles[i].index_st[j]); + } + + SafeWrite (modelouthandle, &tri, sizeof(tri)); + } + + // + // write out the frames + // + for (i=0 ; i<model.num_frames ; i++) + { + in = &g_frames[i]; + out = (daliasframe_t *)buffer; + + strcpy (out->name, 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 ; j<model.num_xyz ; j++) + { + // all of these are byte values, so no need to deal with endianness + out->verts[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 ; i<model.num_skins ; i++) + { + ReleaseFile (g_skins[i]); + } + model.num_frames = 0; + return; + } + +// +// write the model output file +// + if (modelname[0]) + sprintf (name, "%s%s", g_outputDir, modelname); + else + sprintf (name, "%s/tris.md2", g_outputDir); + printf ("saving to %s\n", name); + CreatePath (name); + modelouthandle = SafeOpenWrite (name); + +#if 1 + if(jointed != NOT_JOINTED) + WriteJointedModelFile(modelouthandle); + else +#endif + WriteModelFile(modelouthandle); + + printf ("%3dx%3d skin\n", model.skinwidth, model.skinheight); + printf ("First frame boundaries:\n"); + printf (" minimum x: %3f\n", g_frames[0].mins[0]); + printf (" maximum x: %3f\n", g_frames[0].maxs[0]); + printf (" minimum y: %3f\n", g_frames[0].mins[1]); + printf (" maximum y: %3f\n", g_frames[0].maxs[1]); + printf (" minimum z: %3f\n", g_frames[0].mins[2]); + printf (" maximum z: %3f\n", g_frames[0].maxs[2]); + printf ("%4d vertices\n", model.num_xyz); + printf ("%4d triangles\n", model.num_tris); + printf ("%4d frame\n", model.num_frames); + printf ("%4d glverts\n", numglverts); + printf ("%4d glcmd\n", model.num_glcmds); + printf ("%4d skins\n", model.num_skins); + printf ("file size: %d\n", (int)ftell (modelouthandle) ); + printf ("---------------------\n"); + + 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); + + fclose (headerouthandle); + headerouthandle = NULL; +} + + +/* +================================================================= + +ALIAS MODEL DISPLAY LIST GENERATION + +================================================================= +*/ + +int strip_xyz[128]; +int strip_st[128]; +int strip_tris[128]; +int stripcount; + +/* +================ +StripLength +================ +*/ +static int StripLength (int starttri, int startv) +{ + int m1, m2; + int st1, st2; + int j; + dtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) + { + 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]) + 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 ; j<model.num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + +/* +=========== +FanLength +=========== +*/ +static int FanLength (int starttri, int startv) +{ + int m1, m2; + int st1, st2; + int j; + dtriangle_t *last, *check; + int k; + + used[starttri] = 2; + + last = &triangles[starttri]; + + strip_xyz[0] = last->index_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<model.num_tris ; j++, check++) + { + 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]) + 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<model.num_tris ; j++) + if (used[j] == 2) + used[j] = 0; + + return stripcount; +} + + + +/* +================ +BuildGlCmds + +Generate a list of trifans or strips +for the model, which holds for all frames +================ +*/ +static void BuildGlCmds (void) +{ + int i, j, k; + int startv; + float s, t; + int len, bestlen, besttype; + int best_xyz[1024]; + int best_st[1024]; + int best_tris[1024]; + int type; + + // + // build tristrips + // + numcommands = 0; + numglverts = 0; + memset (used, 0, sizeof(used)); + for (i=0 ; i<model.num_tris ; i++) + { + // pick an unused triangle and start the trifan + if (used[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); + else + len = FanLength (i, startv); + if (len > bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j<bestlen+2 ; j++) + { + best_st[j] = strip_st[j]; + best_xyz[j] = strip_xyz[j]; + } + for (j=0 ; j<bestlen ; j++) + best_tris[j] = strip_tris[j]; + } + } + } + + // mark the tris on the best strip/fan as used + for (j=0 ; j<bestlen ; j++) + used[best_tris[j]] = 1; + + if (besttype == 1) + commands[numcommands++] = (bestlen+2); + else + commands[numcommands++] = -(bestlen+2); + + numglverts += bestlen+2; + + for (j=0 ; j<bestlen+2 ; j++) + { + // emit a vertex into the reorder buffer + k = best_st[j]; + + // emit s/t coords into the commands stream + s = base_st[k].s; + t = base_st[k].t; + + s = (s + 0.5) / model.skinwidth; + t = (t + 0.5) / model.skinheight; + + *(float *)&commands[numcommands++] = s; + *(float *)&commands[numcommands++] = t; + *(int *)&commands[numcommands++] = best_xyz[j]; + } + } + + commands[numcommands++] = 0; // end of list marker +} + + +/* +=============================================================== + +BASE FRAME SETUP + +=============================================================== +*/ + +/* +============ +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 +============ +*/ +#if 0 +static void OldBuildST (triangle_t *ptri, int numtri) +{ + int i, j; + int width, height, iwidth, iheight, swidth; + float basex, basey; + float s_scale, t_scale; + float scale; + vec3_t mins, maxs; + float *pbasevert; + vec3_t vtemp1, vtemp2, normal; + + // + // find bounds of all the verts on the base frame + // + ClearBounds (mins, maxs); + + for (i=0 ; i<numtri ; i++) + for (j=0 ; j<3 ; j++) + AddPointToBounds (ptri[i].verts[j], mins, maxs); + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + 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<numtri ; i++) + { + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + if (normal[1] > 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<numtri ; i++) + for (j=0 ; j<3 ; j++) + AddPointToBounds (ptri[i].verts[j], mins, maxs); + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + + scWidth = (ScaleWidth/2)*SCALE_ADJUST_FACTOR; + 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) + 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<numtri ; i++) + { + if (ptri[i].HasUV) + { + for (j=0 ; j<3 ; j++) + { + triangle_st[i][j][0] = Q_rint(ptri[i].uv[j][0]*iwidth); + triangle_st[i][j][1] = Q_rint((1.0f-ptri[i].uv[j][1])*iheight); + } + } + else + { + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + if (normal[1] > 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<model.num_tris ; i++) + { + for (j=0 ; j<3 ; j++) + { + // get the xyz index + for (k=0 ; k<model.num_xyz ; k++) + if (VectorCompare (ptri[i].verts[j], base_xyz[k])) + break; // this vertex is already in the base vertex list + + if (k == model.num_xyz) + { // new index + VectorCopy (ptri[i].verts[j], base_xyz[model.num_xyz]); + + if(clustered) + ReplaceClusterIndex(k, ptri[i].indicies[j], (int **)&clusters, (IntListNode_t **)&vertLists, (int *)&num_verts, (int *)&new_num_verts); + + model.num_xyz++; + } + + triangles[i].index_xyz[j] = k; + + // get the st index + for (k=0 ; k<model.num_st ; k++) + if (triangle_st[i][j][0] == base_st[k].s + && triangle_st[i][j][1] == base_st[k].t) + break; // this vertex is already in the base vertex list + + if (k == model.num_st) + { // new index + base_st[model.num_st].s = triangle_st[i][j][0]; + base_st[model.num_st].t = triangle_st[i][j][1]; + model.num_st++; + } + + triangles[i].index_st[j] = k; + } + } + + // build triangle strips / fans + BuildGlCmds (); +} + +//=============================================================== + +char *FindFrameFile (char *frame) +{ + int time1; + char file1[1024]; + static char retname[1024]; + char base[32]; + char suffix[32]; + 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; + + 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 ; i<model.num_xyz ; i++) + { + vnorms[i].numnormals = 0; + VectorClear (vnorms[i].normalsum); + } + ClearBounds (fr->mins, 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 ; i<num_tris ; i++) + { + vec3_t vtemp1, vtemp2, normal; + float ftemp; + + VectorSubtract (ptri[i].verts[0], ptri[i].verts[1], vtemp1); + VectorSubtract (ptri[i].verts[2], ptri[i].verts[1], vtemp2); + CrossProduct (vtemp1, vtemp2, normal); + + VectorNormalize (normal, normal); + + // rotate the normal so the model faces down the positive x axis + ftemp = normal[0]; + normal[0] = -normal[1]; + normal[1] = ftemp; + + for (j=0 ; j<3 ; j++) + { + index_xyz = triangles[i].index_xyz[j]; + + // rotate the vertices so the model faces down the positive x axis + // also adjust the vertices to the desired origin + ptrivert[index_xyz].v[0] = ((-ptri[i].verts[j][1]) * scale_up) + + adjust[0]; + ptrivert[index_xyz].v[1] = (ptri[i].verts[j][0] * scale_up) + + adjust[1]; + ptrivert[index_xyz].v[2] = (ptri[i].verts[j][2] * scale_up) + + adjust[2]; + + AddPointToBounds (ptrivert[index_xyz].v, fr->mins, 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<model.num_xyz ; i++) + { + int j; + vec3_t v; + float maxdot; + int maxdotindex; + int c; + + c = vnorms[i].numnormals; + if (!c) + Error ("Vertex with no triangles attached"); + + VectorScale (vnorms[i].normalsum, 1.0/c, v); + VectorNormalize (v, v); + + maxdot = -999999.0; + maxdotindex = -1; + + for (j=0 ; j<NUMVERTEXNORMALS ; j++) + { + float dot; + + dot = DotProduct (v, avertexnormals[j]); + if (dot > 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<model.skinheight ; y++) + { + memcpy (cropped+y*model.skinwidth, + pixels+y*width, model.skinwidth); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, model.skinwidth, + model.skinheight, palette); + + free (pixels); + free (palette); + free (cropped); +} + + +/* +================= +Cmd_Origin +================= +*/ +void Cmd_Origin (void) +{ + // rotate points into frame of reference so model points down the + // positive x axis + GetScriptToken (false); + adjust[1] = -atof (token); + + GetScriptToken (false); + adjust[0] = atof (token); + + GetScriptToken (false); + adjust[2] = -atof (token); +} + + +/* +================= +Cmd_ScaleUp +================= +*/ +void Cmd_ScaleUp (void) +{ + GetScriptToken (false); + scale_up = atof (token); + if (g_skipmodel || g_release || g_archive) + return; + + printf ("Scale up: %f\n", scale_up); +} + + +/* +================= +Cmd_Skinsize + +Set a skin size other than the default +================= +*/ +void Cmd_Skinsize (void) +{ + GetScriptToken (false); + g_fixedwidth = atoi(token); + GetScriptToken (false); + g_fixedheight = atoi(token); +} + +/* +================= +Cmd_Modelname + +Gives a different name/location for the file, instead of the cddir +================= +*/ +void Cmd_Modelname (void) +{ + GetScriptToken (false); + strcpy (modelname, token); +} + +/* +=============== +Cmd_Cd +=============== +*/ +void Cmd_Cd (void) +{ + char temp[256]; + + FinishModel (); + ClearModel (); + + GetScriptToken (false); + + // this is a silly mess... + sprintf (cdpartial, "models/%s", token); + sprintf (cdarchive, "%smodels/%s", gamedir+strlen(qdir), token); + sprintf (cddir, "%s%s", gamedir, cdpartial); + + // Since we also changed directories on the output side (for mirror) make sure the outputdir is set properly too. + sprintf(temp, "%s%s", g_outputDir, cdpartial); + strcpy(g_outputDir, temp); + + // 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 monsters) + if (!g_only[0]) + return; + if (strncmp(token, g_only, strlen(g_only))) + { + g_skipmodel = true; + printf ("skipping %s\n", cdpartial); + } +} + +/* +================= +Cmd_Cluster +================= +*/ +void Cmd_Cluster() +{ + 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); + + LoadClusters(file1, (int **)&clusters, (int *)&num_verts, jointed); + + new_num_verts[0] = num_verts[0]; + + clustered = 1; +} + +// Model construction cover functions. +void MODELCMD_Modelname (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + Cmd_Modelname (); +/* + switch(modeltype) + { + case MODEL_MD2: + Cmd_Modelname (); + break; + case MODEL_FM: + Cmd_FMModelname (); + break; + } +*/ +} + +void MODELCMD_Cd (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Cd (); + break; + case MODEL_FM: + Cmd_FMCd (); + break; + } +} + +void MODELCMD_Origin (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + Cmd_Origin (); +/* switch(modeltype) + { + case MODEL_MD2: + Cmd_Origin (); + break; + case MODEL_FM: + Cmd_FMOrigin (); + break; + } +*/ +} + +void MODELCMD_Cluster (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Cluster (); + break; + case MODEL_FM: + Cmd_FMCluster (); + break; + } +} + +void MODELCMD_Base (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Base (); + break; + case MODEL_FM: + Cmd_FMBase (false); + break; + } +} + +void MODELCMD_BaseST (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Base (); + break; + case MODEL_FM: + Cmd_FMBase (true); + break; + } +} + +void MODELCMD_ScaleUp (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + Cmd_ScaleUp (); +/* switch(modeltype) + { + case MODEL_MD2: + Cmd_ScaleUp (); + break; + case MODEL_FM: + Cmd_FMScaleUp (); + break; + } +*/ +} + +void MODELCMD_Frame (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Frame (); + break; + case MODEL_FM: + Cmd_FMFrame (); + break; + } +} + +void MODELCMD_Skin (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + Cmd_Skin (); + break; + case MODEL_FM: + Cmd_FMSkin (); + break; + } +} + +void MODELCMD_Skinsize (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + Cmd_Skinsize (); +/* + switch(modeltype) + { + case MODEL_MD2: + Cmd_Skinsize (); + break; + case MODEL_FM: + Cmd_FMSkinsize (); + break; + } +*/ +} + +void MODELCMD_Skeleton (int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + break; + case MODEL_FM: + Cmd_FMSkeleton (); + break; + } +} + +void MODELCMD_BeginGroup(int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + break; + case MODEL_FM: + Cmd_FMBeginGroup(); + break; + } +} + +void MODELCMD_EndGroup(int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + break; + case MODEL_FM: + Cmd_FMEndGroup(); + break; + } +} + +void MODELCMD_Referenced(int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + break; + case MODEL_FM: + Cmd_FMReferenced(); + break; + } +} + +void MODELCMD_NodeOrder(int modeltype) +{ + if (g_forcemodel) + modeltype = g_forcemodel; + + switch(modeltype) + { + case MODEL_MD2: + break; + case MODEL_FM: + Cmd_FMNodeOrder(); + break; + } +} diff --git a/tools/quake2/qdata_heretic2/pics.c b/tools/quake2/qdata_heretic2/pics.c index d227f264..70ff7d52 100644 --- a/tools/quake2/qdata_heretic2/pics.c +++ b/tools/quake2/qdata_heretic2/pics.c @@ -1,198 +1,198 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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" - -byte *byteimage, *lbmpalette; -int byteimagewidth, byteimageheight; - -qboolean TrueColorImage; -unsigned *longimage; -int longimagewidth, longimageheight; - -char pic_prefix[1024]; -extern char *g_outputDir; - -/* -=============== -Cmd_Pic -=============== -*/ - -void Cmd_Pic (void) -{ - int xl,yl,xh,yh,w,h; - byte *dest, *source; - int flags, value, contents; - char lumpname[128]; - char animname[128]; - byte buffer[256*256]; - unsigned bufferl[256*256]; - char filename[1024]; - unsigned *destl, *sourcel; - int linedelta, x, y; - int size; - miptex_t *qtex; - miptex32_t *qtex32; - float scale_x, scale_y; - - 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; - - animname[0] = 0; - - scale_x = scale_y = 0.5; - - if (TrueColorImage) - { - sprintf (filename, "%spics/%s/%s.m32", g_outputDir, pic_prefix, lumpname); - 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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *destl++ = *sourcel++; // RGBA - } - sourcel += linedelta; - } - - qtex32 = CreateMip32(bufferl, w, h, &size, false); - - qtex32->flags |= 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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *dest++ = *source++; - } - source += linedelta; - } - - qtex = CreateMip(buffer, w, h, lbmpalette, &size, false); - - qtex->flags = 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); -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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" + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +qboolean TrueColorImage; +unsigned *longimage; +int longimagewidth, longimageheight; + +char pic_prefix[1024]; +extern char *g_outputDir; + +/* +=============== +Cmd_Pic +=============== +*/ + +void Cmd_Pic (void) +{ + int xl,yl,xh,yh,w,h; + byte *dest, *source; + int flags, value, contents; + char lumpname[128]; + char animname[128]; + byte buffer[256*256]; + unsigned bufferl[256*256]; + char filename[1024]; + unsigned *destl, *sourcel; + int linedelta, x, y; + int size; + miptex_t *qtex; + miptex32_t *qtex32; + float scale_x, scale_y; + + 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; + + animname[0] = 0; + + scale_x = scale_y = 0.5; + + if (TrueColorImage) + { + sprintf (filename, "%spics/%s/%s.m32", g_outputDir, pic_prefix, lumpname); + 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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *destl++ = *sourcel++; // RGBA + } + sourcel += linedelta; + } + + qtex32 = CreateMip32(bufferl, w, h, &size, false); + + qtex32->flags |= 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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + qtex = CreateMip(buffer, w, h, lbmpalette, &size, false); + + qtex->flags = 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 index b264f96a..e51d2e29 100644 --- a/tools/quake2/qdata_heretic2/qcommon/angles.h +++ b/tools/quake2/qdata_heretic2/qcommon/angles.h @@ -1,76 +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 ' - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index d329d1a6..831f37cf 100644 --- a/tools/quake2/qdata_heretic2/qcommon/arrayedlist.h +++ b/tools/quake2/qdata_heretic2/qcommon/arrayedlist.h @@ -1,71 +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 <assert.h> - -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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> + +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 index c3cf6076..db86ac67 100644 --- a/tools/quake2/qdata_heretic2/qcommon/flex.h +++ b/tools/quake2/qdata_heretic2/qcommon/flex.h @@ -1,33 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index f33efa47..f52d922c 100644 --- a/tools/quake2/qdata_heretic2/qcommon/fmodel.h +++ b/tools/quake2/qdata_heretic2/qcommon/fmodel.h @@ -1,202 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index a2778f0b..aecfee64 100644 --- a/tools/quake2/qdata_heretic2/qcommon/h2common.h +++ b/tools/quake2/qdata_heretic2/qcommon/h2common.h @@ -1,26 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index df98896f..7194bf3c 100644 --- a/tools/quake2/qdata_heretic2/qcommon/placement.h +++ b/tools/quake2/qdata_heretic2/qcommon/placement.h @@ -1,38 +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 - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 14206cb0..63507f72 100644 --- a/tools/quake2/qdata_heretic2/qcommon/q_typedef.h +++ b/tools/quake2/qdata_heretic2/qcommon/q_typedef.h @@ -1,63 +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 - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index cb0a4b53..9466b796 100644 --- a/tools/quake2/qdata_heretic2/qcommon/qfiles.h +++ b/tools/quake2/qdata_heretic2/qcommon/qfiles.h @@ -1,604 +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; - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index c26b1ae9..3145c052 100644 --- a/tools/quake2/qdata_heretic2/qcommon/reference.c +++ b/tools/quake2/qdata_heretic2/qcommon/reference.c @@ -1,124 +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 <string.h> -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <string.h> +#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 index 9acdc56b..c61a1cec 100644 --- a/tools/quake2/qdata_heretic2/qcommon/reference.h +++ b/tools/quake2/qdata_heretic2/qcommon/reference.h @@ -1,126 +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 - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index cc5293c5..a48f372d 100644 --- a/tools/quake2/qdata_heretic2/qcommon/resourcemanager.c +++ b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.c @@ -1,159 +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 <stdio.h> -#include "resourcemanager.h" -#include <assert.h> - -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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include "resourcemanager.h" +#include <assert.h> + +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 index b8f1eb89..1891d49a 100644 --- a/tools/quake2/qdata_heretic2/qcommon/resourcemanager.h +++ b/tools/quake2/qdata_heretic2/qcommon/resourcemanager.h @@ -1,47 +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 <stdlib.h> // 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); - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> // 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 index c1db9608..8e2f685d 100644 --- a/tools/quake2/qdata_heretic2/qcommon/skeletons.c +++ b/tools/quake2/qdata_heretic2/qcommon/skeletons.c @@ -1,232 +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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 83793592..6f340941 100644 --- a/tools/quake2/qdata_heretic2/qcommon/skeletons.h +++ b/tools/quake2/qdata_heretic2/qcommon/skeletons.h @@ -1,107 +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 <stdlib.h> // 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]; - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> // 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 index 830325f1..c1db5da6 100644 --- a/tools/quake2/qdata_heretic2/qd_fmodel.h +++ b/tools/quake2/qdata_heretic2/qd_fmodel.h @@ -1,61 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 18868f1e..f36fb1df 100644 --- a/tools/quake2/qdata_heretic2/qd_skeletons.c +++ b/tools/quake2/qdata_heretic2/qd_skeletons.c @@ -1,1291 +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 <assert.h> -#include <math.h> -#include <memory.h> - - -// 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<REF_MAX_POINTS; i++) - { - if (ScriptTokenAvailable()) - { // There is yet another reference point waiting. - GetScriptToken(false); - strcpy(RefPointNameList[i], token); - } - else - { - break; - } - } - - RefPointNum = i; - - if (RefPointNum > 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> +#include <math.h> +#include <memory.h> + + +// 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<REF_MAX_POINTS; i++) + { + if (ScriptTokenAvailable()) + { // There is yet another reference point waiting. + GetScriptToken(false); + strcpy(RefPointNameList[i], token); + } + else + { + break; + } + } + + RefPointNum = i; + + if (RefPointNum > 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 index 867e9602..59261432 100644 --- a/tools/quake2/qdata_heretic2/qd_skeletons.h +++ b/tools/quake2/qdata_heretic2/qd_skeletons.h @@ -1,84 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index d8488f69..64edf0a3 100644 --- a/tools/quake2/qdata_heretic2/qdata.c +++ b/tools/quake2/qdata_heretic2/qdata.c @@ -1,730 +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 <sys/types.h> -#ifdef NeXT -#include <sys/dir.h> -#else -#include <dirent.h> -#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 ; i<count ; i++) - { - ent = namelist[i]; - name = ent->d_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<numrtex ; i++) - if (!Q_strcasecmp(name, rtex[i])) - return; - - if (numrtex == MAX_RTEX) - Error ("numrtex == MAX_RTEX"); - - strcpy (rtex[i], name); - numrtex++; - - sprintf (path, "textures/%s.wal", name); - ReleaseFile (path); -} - -/* -=============== -Cmd_Maps - -Only relevent for release and pak files. -Releases the .bsp files for the maps, and scans all of the files to -build a list of all textures used, which are then released. -=============== -*/ -void Cmd_Maps (void) -{ - char map[1024]; - int i; - - while (ScriptTokenAvailable ()) - { - GetScriptToken (false); - sprintf (map, "maps/%s.bsp", token); - ReleaseFile (map); - - if (!g_release) - continue; - - // get all the texture references - sprintf (map, "%smaps/%s.bsp", gamedir, token); - LoadBSPFileTexinfo (map); - for (i=0 ; i<numtexinfo ; i++) - ReleaseTexture (texinfo[i].texture); - } -} - - -//============================================================== - -/* -=============== -ParseScript -=============== -*/ -void ParseScript (void) -{ - while (1) - { - do - { // look for a line starting with a $ command - GetScriptToken (true); - if (endofscript) - return; - if (token[0] == '$') - break; - while (ScriptTokenAvailable()) - GetScriptToken (false); - } while (1); - - // - // model commands - // - if (!strcmp (token, "$modelname")) - MODELCMD_Modelname (MODEL_MD2); - else if (!strcmp (token, "$cd")) - MODELCMD_Cd (MODEL_MD2); - else if (!strcmp (token, "$origin")) - MODELCMD_Origin (MODEL_MD2); - else if (!strcmp (token, "$cluster")) - MODELCMD_Cluster (MODEL_MD2); - else if (!strcmp (token, "$base")) - MODELCMD_Base (MODEL_MD2); - else if (!strcmp (token, "$scale")) - MODELCMD_ScaleUp (MODEL_MD2); - else if (!strcmp (token, "$frame")) - MODELCMD_Frame (MODEL_MD2); - else if (!strcmp (token, "$skin")) - MODELCMD_Skin (MODEL_MD2); - else if (!strcmp (token, "$skinsize")) - MODELCMD_Skinsize (MODEL_MD2); - // - // flexible model commands - // - else if (!strcmp (token, "$fm_modelname")) - MODELCMD_Modelname (MODEL_FM); - else if (!strcmp (token, "$fm_base")) - MODELCMD_Base (MODEL_FM); - else if (!strcmp (token, "$fm_basest")) - MODELCMD_BaseST (MODEL_FM); - else if (!strcmp (token, "$fm_cd")) - MODELCMD_Cd (MODEL_FM); - else if (!strcmp (token, "$fm_origin")) - MODELCMD_Origin (MODEL_FM); - else if (!strcmp (token, "$fm_cluster")) - MODELCMD_Cluster (MODEL_FM); - else if (!strcmp (token, "$fm_skeleton")) - MODELCMD_Skeleton (MODEL_FM); - else if (!strcmp (token, "$fm_scale")) - MODELCMD_ScaleUp (MODEL_FM); - else if (!strcmp (token, "$fm_frame")) - MODELCMD_Frame (MODEL_FM); - else if (!strcmp (token, "$fm_skeletal_frame")) // left in for compadibility with qdt already using fm_skeletal_frame - MODELCMD_Frame (MODEL_FM); - else if (!strcmp (token, "$fm_skin")) - MODELCMD_Skin (MODEL_FM); - else if (!strcmp (token, "$fm_skinsize")) - MODELCMD_Skinsize (MODEL_FM); - else if (!strcmp (token, "$fm_begin_group")) - MODELCMD_BeginGroup(MODEL_FM); - else if (!strcmp (token, "$fm_end_group")) - MODELCMD_EndGroup(MODEL_FM); - else if (!strcmp (token, "$fm_referenced")) - MODELCMD_Referenced(MODEL_FM); - else if (!strcmp (token, "$fm_node_order")) - MODELCMD_NodeOrder(MODEL_FM); - - // - // sprite commands - // - else if (!strcmp (token, "$spritename")) - Cmd_SpriteName (); - else if (!strcmp (token, "$sprdir")) - Cmd_Sprdir (); - else if (!strcmp (token, "$load")) - Cmd_Load (); - else if (!strcmp (token, "$spriteframe")) - Cmd_SpriteFrame (); - // - // image commands - // - else if (!strcmpi (token, "$grab")) - Cmd_Grab (); - else if (!strcmpi (token, "$raw")) - Cmd_Raw (); - else if (!strcmpi (token, "$colormap")) - Cmd_Colormap (); - else if (!strcmpi (token, "$mippal")) - Cmd_Mippal (); - else if (!strcmpi (token, "$mipdir")) - Cmd_Mipdir (); - else if (!strcmpi (token, "$mip")) - Cmd_Mip (); - else if (!strcmp (token, "$environment")) - Cmd_Environment (); - // - // pics - // - else if (!strcmp (token, "$picdir")) - Cmd_Picdir (); - else if (!strcmp (token, "$pic")) - Cmd_Pic (); - // - // book - // - else if (!strcmp (token, "$bookdir")) - Cmd_Bookdir (); - else if (!strcmp (token, "$book")) - Cmd_Book (); - // - // tmix - // - else if (!strcmp (token, "$texturemix")) - Cmd_TextureMix (); - // - // video - // - else if (!strcmp (token, "$video")) - Cmd_Video (); - // - // misc - // - else if (!strcmp (token, "$file")) - Cmd_File (); - else if (!strcmp (token, "$dir")) - Cmd_Dir (); - else if (!strcmp (token, "$maps")) - Cmd_Maps (); - else if (!strcmp (token, "$alphalight")) - Cmd_Alphalight (); - else if (!strcmp (token, "$inverse16table" )) - Cmd_Inverse16Table(); - else - Error ("bad command %s\n", token); - } -} - -//======================================================= - -/* -============== -main -============== -*/ -int main (int argc, char **argv) -{ - int i; - char path[1024]; - char *basedir; - double starttime, endtime; - - printf ("Qdata Plus : "__TIME__" "__DATE__"\n"); - - starttime = I_FloatTime(); - basedir = NULL; - - TK_Init(); - ExpandWildcards (&argc, &argv); - - for (i=1 ; i<argc ; i++) - { - if (!strcmp(argv[i], "-archive")) - { - // -archive f:/quake2/release/dump_11_30 - archive = true; - strcpy (archivedir, argv[i+1]); - printf ("Archiving source to: %s\n", archivedir); - i++; - } - else if (!strcmp(argv[i], "-release")) - { - g_release = true; - strcpy (g_releasedir, argv[i+1]); - printf ("Copy output to: %s\n", g_releasedir); - i++; - } - else if (!strcmp(argv[i], "-base")) - { - i++; - basedir = argv[i]; - } - else if (!strcmp(argv[i], "-compress")) - { - g_compress_pak = true; - printf ("Compressing pakfile\n"); - } - else if (!strcmp(argv[i], "-pak")) - { - g_release = true; - g_pak = true; - printf ("Building pakfile: %s\n", argv[i+1]); - BeginPak (argv[i+1]); - i++; - } - else if (!strcmp(argv[i], "-only")) - { - strcpy (g_only, argv[i+1]); - printf ("Only grabbing %s\n", g_only); - i++; - } - else if (!strcmpi(argv[i], "-keypress")) - { - g_dokeypress = true; - } - else if (!strcmp(argv[i], "-3ds")) - { - do3ds = true; - printf ("loading .3ds files\n"); - } - else if (!strcmp(argv[i], "-materialfile")) - { - strcpy(g_materialFile, argv[i+1]); - printf("Setting material file to %s\n", g_materialFile); - i++; - } -/* else if (!strcmpi(argv[i], "-newgen")) - { - if (i < argc-4) - { - printf("run new triangle grouping routine here\n"); - NewGen(argv[i+1],argv[i+2],atoi(argv[i+3]),atoi(argv[i+4])); - } - else - { - printf("qdata -newskin <base.hrc> <skin.pcx> 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 <base.hrc> <skin.pcx> <desired width> <desired height>\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 <directory>]\n" - " [-release <directory>]\n" - " [-base <directory>]\n" - " [-compress]\n" - " [-pak <file>]\n" - " [-only <model>]\n" - " [-keypress]\n" - " [-3ds]\n" - " [-materialfile <file>]\n" - " [-noopts]\n" - " [-md2]\n" - " [-fm]\n" - " [-verbose]\n" - " [-ignoreUV]\n" - " [-oldskin]\n" - " [-publish]\n" - " [-nomkdir]\n" - " file.qdt\n" - "or\n" - " qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>"); - } - - if (do3ds) - trifileext = ext_3ds; - else - trifileext = ext_tri; - - for ( ; i<argc ; i++) - { - printf ("--------------- %s ---------------\n", argv[i]); - // load the script - strcpy (path, argv[i]); - DefaultExtension (path, ".qdt"); - DefaultExtension(g_materialFile, ".mat"); - SetQdirFromPath (path); - - printf("workingdir='%s'\n", gamedir); - if (basedir) - { - qdir[0] = 0; - g_outputDir = basedir; - } - - printf("outputdir='%s'\n", g_outputDir); - - QFile_ReadMaterialTypes(g_materialFile); - LoadScriptFile (ExpandArg(path)); - - // - // parse it - // - ParseScript (); - - // write out the last model - FinishModel (); - FMFinishModel (); - FinishSprite (); - } - - if (total_textures) - { - printf("\n"); - printf("Total textures processed: %d\n",total_textures); - printf("Average size: %d x %d\n",total_x / total_textures, total_y / total_textures); - } - - if (g_pak) - FinishPak (); - - endtime = I_FloatTime(); - printf("Time elapsed: %f\n", endtime-starttime); - - if (g_dokeypress) - { - printf("Success! ... Hit a key: "); - getchar(); - } - - return 0; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#ifdef NeXT +#include <sys/dir.h> +#else +#include <dirent.h> +#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 ; i<count ; i++) + { + ent = namelist[i]; + name = ent->d_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<numrtex ; i++) + if (!Q_strcasecmp(name, rtex[i])) + return; + + if (numrtex == MAX_RTEX) + Error ("numrtex == MAX_RTEX"); + + strcpy (rtex[i], name); + numrtex++; + + sprintf (path, "textures/%s.wal", name); + ReleaseFile (path); +} + +/* +=============== +Cmd_Maps + +Only relevent for release and pak files. +Releases the .bsp files for the maps, and scans all of the files to +build a list of all textures used, which are then released. +=============== +*/ +void Cmd_Maps (void) +{ + char map[1024]; + int i; + + while (ScriptTokenAvailable ()) + { + GetScriptToken (false); + sprintf (map, "maps/%s.bsp", token); + ReleaseFile (map); + + if (!g_release) + continue; + + // get all the texture references + sprintf (map, "%smaps/%s.bsp", gamedir, token); + LoadBSPFileTexinfo (map); + for (i=0 ; i<numtexinfo ; i++) + ReleaseTexture (texinfo[i].texture); + } +} + + +//============================================================== + +/* +=============== +ParseScript +=============== +*/ +void ParseScript (void) +{ + while (1) + { + do + { // look for a line starting with a $ command + GetScriptToken (true); + if (endofscript) + return; + if (token[0] == '$') + break; + while (ScriptTokenAvailable()) + GetScriptToken (false); + } while (1); + + // + // model commands + // + if (!strcmp (token, "$modelname")) + MODELCMD_Modelname (MODEL_MD2); + else if (!strcmp (token, "$cd")) + MODELCMD_Cd (MODEL_MD2); + else if (!strcmp (token, "$origin")) + MODELCMD_Origin (MODEL_MD2); + else if (!strcmp (token, "$cluster")) + MODELCMD_Cluster (MODEL_MD2); + else if (!strcmp (token, "$base")) + MODELCMD_Base (MODEL_MD2); + else if (!strcmp (token, "$scale")) + MODELCMD_ScaleUp (MODEL_MD2); + else if (!strcmp (token, "$frame")) + MODELCMD_Frame (MODEL_MD2); + else if (!strcmp (token, "$skin")) + MODELCMD_Skin (MODEL_MD2); + else if (!strcmp (token, "$skinsize")) + MODELCMD_Skinsize (MODEL_MD2); + // + // flexible model commands + // + else if (!strcmp (token, "$fm_modelname")) + MODELCMD_Modelname (MODEL_FM); + else if (!strcmp (token, "$fm_base")) + MODELCMD_Base (MODEL_FM); + else if (!strcmp (token, "$fm_basest")) + MODELCMD_BaseST (MODEL_FM); + else if (!strcmp (token, "$fm_cd")) + MODELCMD_Cd (MODEL_FM); + else if (!strcmp (token, "$fm_origin")) + MODELCMD_Origin (MODEL_FM); + else if (!strcmp (token, "$fm_cluster")) + MODELCMD_Cluster (MODEL_FM); + else if (!strcmp (token, "$fm_skeleton")) + MODELCMD_Skeleton (MODEL_FM); + else if (!strcmp (token, "$fm_scale")) + MODELCMD_ScaleUp (MODEL_FM); + else if (!strcmp (token, "$fm_frame")) + MODELCMD_Frame (MODEL_FM); + else if (!strcmp (token, "$fm_skeletal_frame")) // left in for compadibility with qdt already using fm_skeletal_frame + MODELCMD_Frame (MODEL_FM); + else if (!strcmp (token, "$fm_skin")) + MODELCMD_Skin (MODEL_FM); + else if (!strcmp (token, "$fm_skinsize")) + MODELCMD_Skinsize (MODEL_FM); + else if (!strcmp (token, "$fm_begin_group")) + MODELCMD_BeginGroup(MODEL_FM); + else if (!strcmp (token, "$fm_end_group")) + MODELCMD_EndGroup(MODEL_FM); + else if (!strcmp (token, "$fm_referenced")) + MODELCMD_Referenced(MODEL_FM); + else if (!strcmp (token, "$fm_node_order")) + MODELCMD_NodeOrder(MODEL_FM); + + // + // sprite commands + // + else if (!strcmp (token, "$spritename")) + Cmd_SpriteName (); + else if (!strcmp (token, "$sprdir")) + Cmd_Sprdir (); + else if (!strcmp (token, "$load")) + Cmd_Load (); + else if (!strcmp (token, "$spriteframe")) + Cmd_SpriteFrame (); + // + // image commands + // + else if (!strcmpi (token, "$grab")) + Cmd_Grab (); + else if (!strcmpi (token, "$raw")) + Cmd_Raw (); + else if (!strcmpi (token, "$colormap")) + Cmd_Colormap (); + else if (!strcmpi (token, "$mippal")) + Cmd_Mippal (); + else if (!strcmpi (token, "$mipdir")) + Cmd_Mipdir (); + else if (!strcmpi (token, "$mip")) + Cmd_Mip (); + else if (!strcmp (token, "$environment")) + Cmd_Environment (); + // + // pics + // + else if (!strcmp (token, "$picdir")) + Cmd_Picdir (); + else if (!strcmp (token, "$pic")) + Cmd_Pic (); + // + // book + // + else if (!strcmp (token, "$bookdir")) + Cmd_Bookdir (); + else if (!strcmp (token, "$book")) + Cmd_Book (); + // + // tmix + // + else if (!strcmp (token, "$texturemix")) + Cmd_TextureMix (); + // + // video + // + else if (!strcmp (token, "$video")) + Cmd_Video (); + // + // misc + // + else if (!strcmp (token, "$file")) + Cmd_File (); + else if (!strcmp (token, "$dir")) + Cmd_Dir (); + else if (!strcmp (token, "$maps")) + Cmd_Maps (); + else if (!strcmp (token, "$alphalight")) + Cmd_Alphalight (); + else if (!strcmp (token, "$inverse16table" )) + Cmd_Inverse16Table(); + else + Error ("bad command %s\n", token); + } +} + +//======================================================= + +/* +============== +main +============== +*/ +int main (int argc, char **argv) +{ + int i; + char path[1024]; + char *basedir; + double starttime, endtime; + + printf ("Qdata Plus : "__TIME__" "__DATE__"\n"); + + starttime = I_FloatTime(); + basedir = NULL; + + TK_Init(); + ExpandWildcards (&argc, &argv); + + for (i=1 ; i<argc ; i++) + { + if (!strcmp(argv[i], "-archive")) + { + // -archive f:/quake2/release/dump_11_30 + archive = true; + strcpy (archivedir, argv[i+1]); + printf ("Archiving source to: %s\n", archivedir); + i++; + } + else if (!strcmp(argv[i], "-release")) + { + g_release = true; + strcpy (g_releasedir, argv[i+1]); + printf ("Copy output to: %s\n", g_releasedir); + i++; + } + else if (!strcmp(argv[i], "-base")) + { + i++; + basedir = argv[i]; + } + else if (!strcmp(argv[i], "-compress")) + { + g_compress_pak = true; + printf ("Compressing pakfile\n"); + } + else if (!strcmp(argv[i], "-pak")) + { + g_release = true; + g_pak = true; + printf ("Building pakfile: %s\n", argv[i+1]); + BeginPak (argv[i+1]); + i++; + } + else if (!strcmp(argv[i], "-only")) + { + strcpy (g_only, argv[i+1]); + printf ("Only grabbing %s\n", g_only); + i++; + } + else if (!strcmpi(argv[i], "-keypress")) + { + g_dokeypress = true; + } + else if (!strcmp(argv[i], "-3ds")) + { + do3ds = true; + printf ("loading .3ds files\n"); + } + else if (!strcmp(argv[i], "-materialfile")) + { + strcpy(g_materialFile, argv[i+1]); + printf("Setting material file to %s\n", g_materialFile); + i++; + } +/* else if (!strcmpi(argv[i], "-newgen")) + { + if (i < argc-4) + { + printf("run new triangle grouping routine here\n"); + NewGen(argv[i+1],argv[i+2],atoi(argv[i+3]),atoi(argv[i+4])); + } + else + { + printf("qdata -newskin <base.hrc> <skin.pcx> 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 <base.hrc> <skin.pcx> <desired width> <desired height>\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 <directory>]\n" + " [-release <directory>]\n" + " [-base <directory>]\n" + " [-compress]\n" + " [-pak <file>]\n" + " [-only <model>]\n" + " [-keypress]\n" + " [-3ds]\n" + " [-materialfile <file>]\n" + " [-noopts]\n" + " [-md2]\n" + " [-fm]\n" + " [-verbose]\n" + " [-ignoreUV]\n" + " [-oldskin]\n" + " [-publish]\n" + " [-nomkdir]\n" + " file.qdt\n" + "or\n" + " qdata -genskin <base.hrc> <skin.pcx> <desired width> <desired height>"); + } + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i<argc ; i++) + { + printf ("--------------- %s ---------------\n", argv[i]); + // load the script + strcpy (path, argv[i]); + DefaultExtension (path, ".qdt"); + DefaultExtension(g_materialFile, ".mat"); + SetQdirFromPath (path); + + printf("workingdir='%s'\n", gamedir); + if (basedir) + { + qdir[0] = 0; + g_outputDir = basedir; + } + + printf("outputdir='%s'\n", g_outputDir); + + QFile_ReadMaterialTypes(g_materialFile); + LoadScriptFile (ExpandArg(path)); + + // + // parse it + // + ParseScript (); + + // write out the last model + FinishModel (); + FMFinishModel (); + FinishSprite (); + } + + if (total_textures) + { + printf("\n"); + printf("Total textures processed: %d\n",total_textures); + printf("Average size: %d x %d\n",total_x / total_textures, total_y / total_textures); + } + + if (g_pak) + FinishPak (); + + endtime = I_FloatTime(); + printf("Time elapsed: %f\n", endtime-starttime); + + if (g_dokeypress) + { + printf("Success! ... Hit a key: "); + getchar(); + } + + return 0; +} + diff --git a/tools/quake2/qdata_heretic2/qdata.h b/tools/quake2/qdata_heretic2/qdata.h index 57f6f896..bbe9c6b3 100644 --- a/tools/quake2/qdata_heretic2/qdata.h +++ b/tools/quake2/qdata_heretic2/qdata.h @@ -1,166 +1,166 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -// qdata.h - - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <sys/stat.h> - -#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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// qdata.h + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <sys/stat.h> + +#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/resource.h b/tools/quake2/qdata_heretic2/resource.h index b71bb50e..14e2fb5b 100644 --- a/tools/quake2/qdata_heretic2/resource.h +++ b/tools/quake2/qdata_heretic2/resource.h @@ -1,18 +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 +//{{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/sprites.c b/tools/quake2/qdata_heretic2/sprites.c index 68514c20..86854063 100644 --- a/tools/quake2/qdata_heretic2/sprites.c +++ b/tools/quake2/qdata_heretic2/sprites.c @@ -1,349 +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<sprite.numframes ; i++) - { - frames[i].width = LittleLong(frames[i].width); - frames[i].height = LittleLong(frames[i].height); - frames[i].origin_x = LittleLong(frames[i].origin_x); - frames[i].origin_y = LittleLong(frames[i].origin_y); - } - SafeWrite (spriteouthandle, frames, sizeof(frames[0])*sprite.numframes); - - fclose (spriteouthandle); - - spritename[0] = 0; // clear for a new sprite - sprite.numframes = 0; -} - - -/* -=============== -Cmd_Load -=============== -*/ -void Cmd_Load (void) -{ - char *name; - - GetScriptToken (false); - - if (g_release) - return; - - name = ExpandPathAndArchive(token); - - // load the image - printf ("loading %s\n", name); - TrueColorImage = LoadAnyImage (name, &byteimage, &lbmpalette, &byteimagewidth, &byteimageheight); - - if (!TrueColorImage) - { -// RemapZero (byteimage, lbmpalette, byteimagewidth, byteimageheight); - } - else - { - if (longimage) - free(longimage); - longimage = (unsigned *)byteimage; - longimagewidth = byteimagewidth; - longimageheight = byteimageheight; - - byteimage = NULL; - byteimagewidth = 0; - byteimageheight = 0; - } -} - - -/* -=============== -Cmd_SpriteFrame -=============== -*/ - -void Cmd_SpriteFrame (void) -{ - int x,y,xl,yl,xh,yh,w,h; - dsprframe_t *pframe; - int ox, oy, linedelta, size; -// byte *cropped; - char filename[1024]; - miptex_t *qtex; - miptex32_t *qtex32; - unsigned *destl, *sourcel; - unsigned bufferl[256*256]; - byte *dest, *source; - byte buffer[256*256]; - - GetScriptToken (false); - xl = atoi (token); - GetScriptToken (false); - yl = atoi (token); - GetScriptToken (false); - w = atoi (token); - GetScriptToken (false); - h = atoi (token); - - // origin offset is optional - if (ScriptTokenAvailable ()) - { - GetScriptToken (false); - ox = atoi (token); - GetScriptToken (false); - oy = atoi (token); - } - else - { - ox = w/2; - oy = h/2; - } - - if ((xl & 0x0f) || (yl & 0x0f) || (w & 0x0f) || (h & 0x0f)) - Error ("Sprite dimensions not multiples of 16\n"); - - if ((w > 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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *destl++ = *sourcel++; // RGBA - } - sourcel += linedelta; - } - - qtex32 = CreateMip32(bufferl, w, h, &size, true); - - qtex32->contents = 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 ; y<yh ; y++) - { - for (x=xl ; x<xh ; x++) - { - *dest++ = *source++; - } - source += linedelta; - } - - qtex = CreateMip(buffer, w, h, lbmpalette, &size, true); - - qtex->flags = 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); -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<sprite.numframes ; i++) + { + frames[i].width = LittleLong(frames[i].width); + frames[i].height = LittleLong(frames[i].height); + frames[i].origin_x = LittleLong(frames[i].origin_x); + frames[i].origin_y = LittleLong(frames[i].origin_y); + } + SafeWrite (spriteouthandle, frames, sizeof(frames[0])*sprite.numframes); + + fclose (spriteouthandle); + + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; +} + + +/* +=============== +Cmd_Load +=============== +*/ +void Cmd_Load (void) +{ + char *name; + + GetScriptToken (false); + + if (g_release) + return; + + name = ExpandPathAndArchive(token); + + // load the image + printf ("loading %s\n", name); + TrueColorImage = LoadAnyImage (name, &byteimage, &lbmpalette, &byteimagewidth, &byteimageheight); + + if (!TrueColorImage) + { +// RemapZero (byteimage, lbmpalette, byteimagewidth, byteimageheight); + } + else + { + if (longimage) + free(longimage); + longimage = (unsigned *)byteimage; + longimagewidth = byteimagewidth; + longimageheight = byteimageheight; + + byteimage = NULL; + byteimagewidth = 0; + byteimageheight = 0; + } +} + + +/* +=============== +Cmd_SpriteFrame +=============== +*/ + +void Cmd_SpriteFrame (void) +{ + int x,y,xl,yl,xh,yh,w,h; + dsprframe_t *pframe; + int ox, oy, linedelta, size; +// byte *cropped; + char filename[1024]; + miptex_t *qtex; + miptex32_t *qtex32; + unsigned *destl, *sourcel; + unsigned bufferl[256*256]; + byte *dest, *source; + byte buffer[256*256]; + + GetScriptToken (false); + xl = atoi (token); + GetScriptToken (false); + yl = atoi (token); + GetScriptToken (false); + w = atoi (token); + GetScriptToken (false); + h = atoi (token); + + // origin offset is optional + if (ScriptTokenAvailable ()) + { + GetScriptToken (false); + ox = atoi (token); + GetScriptToken (false); + oy = atoi (token); + } + else + { + ox = w/2; + oy = h/2; + } + + if ((xl & 0x0f) || (yl & 0x0f) || (w & 0x0f) || (h & 0x0f)) + Error ("Sprite dimensions not multiples of 16\n"); + + if ((w > 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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *destl++ = *sourcel++; // RGBA + } + sourcel += linedelta; + } + + qtex32 = CreateMip32(bufferl, w, h, &size, true); + + qtex32->contents = 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 ; y<yh ; y++) + { + for (x=xl ; x<xh ; x++) + { + *dest++ = *source++; + } + source += linedelta; + } + + qtex = CreateMip(buffer, w, h, lbmpalette, &size, true); + + qtex->flags = 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 index 8e02f8e4..e4496a19 100644 --- a/tools/quake2/qdata_heretic2/svdcmp.c +++ b/tools/quake2/qdata_heretic2/svdcmp.c @@ -1,490 +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 <stdlib.h> -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <math.h> - -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;i<nframes;i++) - { - for (j=0;j<framesize;j++) - da[j+1][i+1]=a[i*framesize+j]; - for (;j<usedfs;j++) - da[j+1][i+1]=0.0; - } - - svdcmp(da,usedfs,nframes,w,v); - - remap = calloc(sizeof(int), (size_t)nframes); - - - for (i=0;i<nframes;i++) - remap[i]=-1; - for (j=0;j<compressedsize;j++) - { - mx=-1.0f; - for (i=0;i<nframes;i++) - { - if (remap[i]<0&&fabs(w[i+1])>mx) - { - 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;i<compressedsize;i++) - { - values[i]=0; - for (j=0;j<framesize;j++) - res[i*framesize+j]=0; - } - } - - for (i=0;i<nframes;i++) - { - if (remap[i]<0) - w[i+1]=0.0; - else - { - values[remap[i]]=(float) w[i+1]; - for (j=0;j<framesize;j++) - res[remap[i]*framesize+j]=(float) da[j+1][i+1]; - } - } - freeVect(w); - freeMatrix(v,nframes); - freeMatrix(da,framesize); - free(remap); -} - -#else - -void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize) -{ - int *remap; - int i,j; - int nrows; - nrows=nframes; - if (nrows<framesize) - nrows=framesize; - double **da=allocMatrix(nrows,framesize); - double **v=allocMatrix(framesize,framesize); - double *w=allocVect(framesize); - float mx; - int bestat; - - for (j=0;j<framesize;j++) - { - for (i=0;i<nframes;i++) - da[j+1][i+1]=a[i*framesize+j]; - for (;i<nrows;i++) - da[j+1][i+1]=0.0; - } - - svdcmp(da,nrows,framesize,w,v); - - remap=new int[framesize]; - - - for (i=0;i<framesize;i++) - remap[i]=-1; - for (j=0;j<compressedsize;j++) - { - mx=-1.0f; - for (i=0;i<framesize;i++) - { - if (remap[i]<0&&fabs(w[i+1])>mx) - { - 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<framesize;i++) - { - if (remap[i]<0) - w[i+1]=0.0; - else - { - values[remap[i]]=w[i+1]; - for (j=0;j<framesize;j++) - res[remap[i]*framesize+j]=v[j+1][i+1]; - } - } - freeVect(w); - freeMatrix(v,framesize); - freeMatrix(da,nrows); - delete[] remap; -} - -#endif - -void DOsvdPlane(float *pnts,int npnts,float *n,float *base) -{ - int i,j; - double **da=allocMatrix(npnts,3); - double **v=allocMatrix(3,3); - double *w=allocVect(3); - float mn=1E30f; - int bestat; - - - assert(npnts>=3); - base[0]=pnts[0]; - base[1]=pnts[1]; - base[2]=pnts[2]; - for (i=1;i<npnts;i++) - { - for (j=0;j<3;j++) - base[j]+=pnts[i*3+j]; - } - base[0]/=(float)(npnts); - base[1]/=(float)(npnts); - base[2]/=(float)(npnts); - - for (i=0;i<3;i++) - { - for (j=0;j<npnts;j++) - da[j+1][i+1]=pnts[j*3+i]-base[i]; - } - - svdcmp(da,npnts,3,w,v); - for (i=0;i<3;i++) - { - if (fabs(w[i+1])<mn) - { - mn=(float) fabs(w[i+1]); - bestat=i; - } - } - n[0]=(float) v[1][bestat+1]; - n[1]=(float) v[2][bestat+1]; - n[2]=(float) v[3][bestat+1]; - freeVect(w); - freeMatrix(v,3); - freeMatrix(da,npnts); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> +#include <stdio.h> +#include <assert.h> +#include <string.h> +#include <math.h> + +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;i<nframes;i++) + { + for (j=0;j<framesize;j++) + da[j+1][i+1]=a[i*framesize+j]; + for (;j<usedfs;j++) + da[j+1][i+1]=0.0; + } + + svdcmp(da,usedfs,nframes,w,v); + + remap = calloc(sizeof(int), (size_t)nframes); + + + for (i=0;i<nframes;i++) + remap[i]=-1; + for (j=0;j<compressedsize;j++) + { + mx=-1.0f; + for (i=0;i<nframes;i++) + { + if (remap[i]<0&&fabs(w[i+1])>mx) + { + 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;i<compressedsize;i++) + { + values[i]=0; + for (j=0;j<framesize;j++) + res[i*framesize+j]=0; + } + } + + for (i=0;i<nframes;i++) + { + if (remap[i]<0) + w[i+1]=0.0; + else + { + values[remap[i]]=(float) w[i+1]; + for (j=0;j<framesize;j++) + res[remap[i]*framesize+j]=(float) da[j+1][i+1]; + } + } + freeVect(w); + freeMatrix(v,nframes); + freeMatrix(da,framesize); + free(remap); +} + +#else + +void DOsvd(float *a,float *res,float *comp,float *values,int nframes,int framesize,int compressedsize) +{ + int *remap; + int i,j; + int nrows; + nrows=nframes; + if (nrows<framesize) + nrows=framesize; + double **da=allocMatrix(nrows,framesize); + double **v=allocMatrix(framesize,framesize); + double *w=allocVect(framesize); + float mx; + int bestat; + + for (j=0;j<framesize;j++) + { + for (i=0;i<nframes;i++) + da[j+1][i+1]=a[i*framesize+j]; + for (;i<nrows;i++) + da[j+1][i+1]=0.0; + } + + svdcmp(da,nrows,framesize,w,v); + + remap=new int[framesize]; + + + for (i=0;i<framesize;i++) + remap[i]=-1; + for (j=0;j<compressedsize;j++) + { + mx=-1.0f; + for (i=0;i<framesize;i++) + { + if (remap[i]<0&&fabs(w[i+1])>mx) + { + 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<framesize;i++) + { + if (remap[i]<0) + w[i+1]=0.0; + else + { + values[remap[i]]=w[i+1]; + for (j=0;j<framesize;j++) + res[remap[i]*framesize+j]=v[j+1][i+1]; + } + } + freeVect(w); + freeMatrix(v,framesize); + freeMatrix(da,nrows); + delete[] remap; +} + +#endif + +void DOsvdPlane(float *pnts,int npnts,float *n,float *base) +{ + int i,j; + double **da=allocMatrix(npnts,3); + double **v=allocMatrix(3,3); + double *w=allocVect(3); + float mn=1E30f; + int bestat; + + + assert(npnts>=3); + base[0]=pnts[0]; + base[1]=pnts[1]; + base[2]=pnts[2]; + for (i=1;i<npnts;i++) + { + for (j=0;j<3;j++) + base[j]+=pnts[i*3+j]; + } + base[0]/=(float)(npnts); + base[1]/=(float)(npnts); + base[2]/=(float)(npnts); + + for (i=0;i<3;i++) + { + for (j=0;j<npnts;j++) + da[j+1][i+1]=pnts[j*3+i]-base[i]; + } + + svdcmp(da,npnts,3,w,v); + for (i=0;i<3;i++) + { + if (fabs(w[i+1])<mn) + { + mn=(float) fabs(w[i+1]); + bestat=i; + } + } + n[0]=(float) v[1][bestat+1]; + n[1]=(float) v[2][bestat+1]; + n[2]=(float) v[3][bestat+1]; + freeVect(w); + freeMatrix(v,3); + freeMatrix(da,npnts); +} diff --git a/tools/quake2/qdata_heretic2/tables.c b/tools/quake2/qdata_heretic2/tables.c index e7bb8ff5..cc78ae9f 100644 --- a/tools/quake2/qdata_heretic2/tables.c +++ b/tools/quake2/qdata_heretic2/tables.c @@ -1,171 +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 -*/ - -#include "qdata.h" - -/* -============================================================================= - -ALPHALIGHT GENERATION - -Find alphamap values that best match modulated lightmap values - -This isn't used anymore, but I'm keeping it around... -============================================================================= -*/ - -unsigned short alphamap[32*32*32]; -unsigned char inverse16to8table[65536]; - -/* -static int FindNearestColor( unsigned int color ) -{ - int i; - int closest_so_far = 0; - float closest_distance_so_far = 100000000; - float d; - float r[2], g[2], b[2]; - - // incoming color is assumed to be in 0xRRGGBB format - r[0] = ( color & 31 ) << 3; - g[0] = ( ( color >> 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 ) ); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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" + +/* +============================================================================= + +ALPHALIGHT GENERATION + +Find alphamap values that best match modulated lightmap values + +This isn't used anymore, but I'm keeping it around... +============================================================================= +*/ + +unsigned short alphamap[32*32*32]; +unsigned char inverse16to8table[65536]; + +/* +static int FindNearestColor( unsigned int color ) +{ + int i; + int closest_so_far = 0; + float closest_distance_so_far = 100000000; + float d; + float r[2], g[2], b[2]; + + // incoming color is assumed to be in 0xRRGGBB format + r[0] = ( color & 31 ) << 3; + g[0] = ( ( color >> 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 index ad1d1902..5bccddf8 100644 --- a/tools/quake2/qdata_heretic2/tmix.c +++ b/tools/quake2/qdata_heretic2/tmix.c @@ -1,698 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index b41c6598..b4ed1a6f 100644 --- a/tools/quake2/qdata_heretic2/video.c +++ b/tools/quake2/qdata_heretic2/video.c @@ -1,1149 +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 <directory> <framedigits> -// ================================== - -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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <directory> <framedigits> +// ================================== + +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 index 58307f85..94491f7f 100644 --- a/tools/quake3/common/aselib.c +++ b/tools/quake3/common/aselib.c @@ -1,965 +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 <assert.h> -#include <stdio.h> -#include <stdlib.h> - -#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(); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <assert.h> +#include <stdio.h> +#include <stdlib.h> + +#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 index 4ff9b234..e3e62adb 100644 --- a/tools/quake3/common/aselib.h +++ b/tools/quake3/common/aselib.h @@ -1,31 +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 ); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index edc3cd65..3ce497a7 100644 --- a/tools/quake3/common/bspfile.c +++ b/tools/quake3/common/bspfile.c @@ -1,706 +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 ; i<num_entities ; i++) { - ep = entities[i].epairs; - if ( !ep ) { - continue; // ent got removed - } - - strcat (end,"{\n"); - end += 2; - - for ( ep = entities[i].epairs ; ep ; ep=ep->next ) { - 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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<num_entities ; i++) { + ep = entities[i].epairs; + if ( !ep ) { + continue; // ent got removed + } + + strcat (end,"{\n"); + end += 2; + + for ( ep = entities[i].epairs ; ep ; ep=ep->next ) { + 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 index b44285f0..c12daca8 100644 --- a/tools/quake3/common/bspfile.h +++ b/tools/quake3/common/bspfile.h @@ -1,121 +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 ); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 17e41032..e2ea8f0a 100644 --- a/tools/quake3/common/cmdlib.c +++ b/tools/quake3/common/cmdlib.c @@ -1,1153 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#endif - -#if defined (__linux__) || defined (__APPLE__) -#include <unistd.h> -#endif - -#ifdef NeXT -#include <libc.h> -#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<myargc;i++) - { - if ( !Q_stricmp(check, myargv[i]) ) - return i; - } - - return 0; -} - - - -/* -================ -Q_filelength -================ -*/ -int Q_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; -} - - -FILE *SafeOpenWrite (const char *filename) -{ - FILE *f; - - f = fopen(filename, "wb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - -FILE *SafeOpenRead (const char *filename) -{ - FILE *f; - - f = fopen(filename, "rb"); - - if (!f) - Error ("Error opening %s: %s",filename,strerror(errno)); - - return f; -} - - -void SafeRead (FILE *f, void *buffer, int count) -{ - if ( fread (buffer, 1, count, f) != (size_t)count) - Error ("File read failure"); -} - - -void SafeWrite (FILE *f, const void *buffer, int count) -{ - if (fwrite (buffer, 1, count, f) != (size_t)count) - Error ("File write failure"); -} - - -/* -============== -FileExists -============== -*/ -qboolean FileExists (const char *filename) -{ - FILE *f; - - f = fopen (filename, "r"); - if (!f) - return qfalse; - fclose (f); - return qtrue; -} - -/* -============== -LoadFile -============== -*/ -int LoadFile( const char *filename, void **bufferptr ) -{ - FILE *f; - int length; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - buffer = safe_malloc (length+1); - ((char *)buffer)[length] = 0; - SafeRead (f, buffer, length); - fclose (f); - - *bufferptr = buffer; - return length; -} - - -/* -============== -LoadFileBlock -- -rounds up memory allocation to 4K boundry -- -============== -*/ -int LoadFileBlock( const char *filename, void **bufferptr ) -{ - FILE *f; - int length, nBlock, nAllocSize; - void *buffer; - - f = SafeOpenRead (filename); - length = Q_filelength (f); - nAllocSize = length; - nBlock = nAllocSize % MEM_BLOCKSIZE; - if ( nBlock > 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 -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#endif + +#if defined (__linux__) || defined (__APPLE__) +#include <unistd.h> +#endif + +#ifdef NeXT +#include <libc.h> +#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<myargc;i++) + { + if ( !Q_stricmp(check, myargv[i]) ) + return i; + } + + return 0; +} + + + +/* +================ +Q_filelength +================ +*/ +int Q_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; +} + + +FILE *SafeOpenWrite (const char *filename) +{ + FILE *f; + + f = fopen(filename, "wb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + +FILE *SafeOpenRead (const char *filename) +{ + FILE *f; + + f = fopen(filename, "rb"); + + if (!f) + Error ("Error opening %s: %s",filename,strerror(errno)); + + return f; +} + + +void SafeRead (FILE *f, void *buffer, int count) +{ + if ( fread (buffer, 1, count, f) != (size_t)count) + Error ("File read failure"); +} + + +void SafeWrite (FILE *f, const void *buffer, int count) +{ + if (fwrite (buffer, 1, count, f) != (size_t)count) + Error ("File write failure"); +} + + +/* +============== +FileExists +============== +*/ +qboolean FileExists (const char *filename) +{ + FILE *f; + + f = fopen (filename, "r"); + if (!f) + return qfalse; + fclose (f); + return qtrue; +} + +/* +============== +LoadFile +============== +*/ +int LoadFile( const char *filename, void **bufferptr ) +{ + FILE *f; + int length; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + buffer = safe_malloc (length+1); + ((char *)buffer)[length] = 0; + SafeRead (f, buffer, length); + fclose (f); + + *bufferptr = buffer; + return length; +} + + +/* +============== +LoadFileBlock +- +rounds up memory allocation to 4K boundry +- +============== +*/ +int LoadFileBlock( const char *filename, void **bufferptr ) +{ + FILE *f; + int length, nBlock, nAllocSize; + void *buffer; + + f = SafeOpenRead (filename); + length = Q_filelength (f); + nAllocSize = length; + nBlock = nAllocSize % MEM_BLOCKSIZE; + if ( nBlock > 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 index 8c27ab85..7eee55ed 100644 --- a/tools/quake3/common/cmdlib.h +++ b/tools/quake3/common/cmdlib.h @@ -1,160 +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 <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> -#include <ctype.h> -#include <time.h> -#include <stdarg.h> - -#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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <stdarg.h> + +#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 index 8955d35a..7a0d22cf 100644 --- a/tools/quake3/common/imagelib.c +++ b/tools/quake3/common/imagelib.c @@ -1,1220 +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 (count<bpwidth); - - if (count>bpwidth) - 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) - { - if (bmhd.compression == cm_rle1) - body_p = LBMRLEDecompress ((byte *)body_p - , pic_p , bmhd.w); - else if (bmhd.compression == cm_none) - { - memcpy (pic_p,body_p,bmhd.w); - body_p += Align(bmhd.w); - } - } - - } - else - { - // - // unpack ILBM - // - Error ("%s is an interlaced LBM, not packed", filename); - } - break; - } - - LBM_P += Align(chunklength); - } - - free (LBMbuffer); - - *picture = picbuffer; - - if (palette) - *palette = cmapbuffer; -} - - -/* -============================================================================ - - WRITE LBM - -============================================================================ -*/ - -/* -============== -WriteLBMfile -============== -*/ -void WriteLBMfile (const char *filename, byte *data, - int width, int height, byte *palette) -{ - byte *lbm, *lbmptr; - int *formlength, *bmhdlength, *cmaplength, *bodylength; - int length; - bmhd_t basebmhd; - - lbm = lbmptr = safe_malloc (width*height+1000); - -// -// start FORM -// - *lbmptr++ = 'F'; - *lbmptr++ = 'O'; - *lbmptr++ = 'R'; - *lbmptr++ = 'M'; - - formlength = (int*)lbmptr; - lbmptr+=4; // leave space for length - - *lbmptr++ = 'P'; - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = ' '; - -// -// write BMHD -// - *lbmptr++ = 'B'; - *lbmptr++ = 'M'; - *lbmptr++ = 'H'; - *lbmptr++ = 'D'; - - bmhdlength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memset (&basebmhd,0,sizeof(basebmhd)); - basebmhd.w = BigShort((short)width); - basebmhd.h = BigShort((short)height); - basebmhd.nPlanes = BigShort(8); - basebmhd.xAspect = BigShort(5); - basebmhd.yAspect = BigShort(6); - basebmhd.pageWidth = BigShort((short)width); - basebmhd.pageHeight = BigShort((short)height); - - memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); - lbmptr += sizeof(basebmhd); - - length = lbmptr-(byte *)bmhdlength-4; - *bmhdlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write CMAP -// - *lbmptr++ = 'C'; - *lbmptr++ = 'M'; - *lbmptr++ = 'A'; - *lbmptr++ = 'P'; - - cmaplength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,palette,768); - lbmptr += 768; - - length = lbmptr-(byte *)cmaplength-4; - *cmaplength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write BODY -// - *lbmptr++ = 'B'; - *lbmptr++ = 'O'; - *lbmptr++ = 'D'; - *lbmptr++ = 'Y'; - - bodylength = (int *)lbmptr; - lbmptr+=4; // leave space for length - - memcpy (lbmptr,data,width*height); - lbmptr += width*height; - - length = lbmptr-(byte *)bodylength-4; - *bodylength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// done -// - length = lbmptr-(byte *)formlength-4; - *formlength = BigLong(length); - if (length&1) - *lbmptr++ = 0; // pad chunk to even offset - -// -// write output file -// - SaveFile (filename, lbm, lbmptr-lbm); - free (lbm); -} - - -/* -============================================================================ - -LOAD PCX - -============================================================================ -*/ - -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; - - -/* -============== -LoadPCX -============== -*/ - -/* RR2DO2 */ -#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;} - -void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height ) -{ - byte *raw; - pcx_t *pcx; - int x, y, lsize; - int len; - int dataByte, runLength; - byte *out, *pix; - - - /* load the file */ - len = vfsLoadFile (filename, (void **)&raw, 0); - if( len == -1 ) - Error( "LoadPCX: Couldn't read %s", filename ); - - - /* parse the PCX file */ - pcx = (pcx_t *)raw; - raw = &pcx->data; - - 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<height ; i++) - { - for (j=0 ; j<width ; j++) - { - if ( (*data & 0xc0) != 0xc0) - *pack++ = *data++; - else - { - *pack++ = 0xc1; - *pack++ = *data++; - } - } - } - - // write the palette - *pack++ = 0x0c; // palette ID byte - for (i=0 ; i<768 ; i++) - *pack++ = *palette++; - -// write output file - length = pack - (byte *)pcx; - SaveFile (filename, pcx, length); - - free (pcx); -} - -/* -============================================================================ - -LOAD BMP - -============================================================================ -*/ - - -/* - -// we can't just use these structures, because -// compiler structure alignment will not be portable -// on this unaligned stuff - -typedef struct tagBITMAPFILEHEADER { // bmfh - WORD bfType; // BM - DWORD bfSize; - WORD bfReserved1; - WORD bfReserved2; - DWORD bfOffBits; -} BITMAPFILEHEADER; - -typedef struct tagBITMAPINFOHEADER{ // bmih - DWORD biSize; - LONG biWidth; - LONG biHeight; - WORD biPlanes; - WORD biBitCount - DWORD biCompression; - DWORD biSizeImage; - LONG biXPelsPerMeter; - LONG biYPelsPerMeter; - DWORD biClrUsed; - DWORD biClrImportant; -} BITMAPINFOHEADER; - -typedef struct tagBITMAPINFO { // bmi - BITMAPINFOHEADER bmiHeader; - RGBQUAD bmiColors[1]; -} BITMAPINFO; - -typedef struct tagBITMAPCOREHEADER { // bmch - DWORD bcSize; - WORD bcWidth; - WORD bcHeight; - WORD bcPlanes; - WORD bcBitCount; -} BITMAPCOREHEADER; - -typedef struct _BITMAPCOREINFO { // bmci - BITMAPCOREHEADER bmciHeader; - RGBTRIPLE bmciColors[1]; -} BITMAPCOREINFO; - -*/ - -/* -============== -LoadBMP -============== -*/ -void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height) -{ - byte *out; - int i; - int bfSize; - int bfOffBits; - int structSize; - int bcWidth; - int bcHeight; - int bcPlanes; - int bcBitCount; - byte bcPalette[1024]; - qboolean flipped; - byte *in; - int len, pos = 0; - - len = vfsLoadFile (filename, (void **)&in, 0); - if (len == -1) - { - Error ("Couldn't read %s", filename); - } - - i = bufLittleShort (in, len, &pos); - if (i != 'B' + ('M'<<8) ) { - Error ("%s is not a bmp file", filename); - } - - bfSize = bufLittleLong (in, len, &pos); - bufLittleShort(in, len, &pos); - bufLittleShort(in, len, &pos); - bfOffBits = bufLittleLong (in, len, &pos); - - // the size will tell us if it is a - // bitmapinfo or a bitmapcore - structSize = bufLittleLong (in, len, &pos); - if (structSize == 40) - { - // bitmapinfo - bcWidth = bufLittleLong(in, len, &pos); - bcHeight= bufLittleLong(in, len, &pos); - bcPlanes = bufLittleShort(in, len, &pos); - bcBitCount = bufLittleShort(in, len, &pos); - - pos += 24; - - if (palette) - { - memcpy (bcPalette, in+pos, 1024); - pos += 1024; - *palette = safe_malloc(768); - - for (i = 0 ; i < 256 ; i++) - { - (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2]; - (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1]; - (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0]; - } - } - } - else if (structSize == 12) - { - // bitmapcore - bcWidth = bufLittleShort(in, len, &pos); - bcHeight= bufLittleShort(in, len, &pos); - bcPlanes = bufLittleShort(in, len, &pos); - bcBitCount = bufLittleShort(in, len, &pos); - - if (palette) - { - memcpy (bcPalette, in+pos, 768); - pos += 768; - *palette = safe_malloc(768); - - for (i = 0 ; i < 256 ; i++) { - (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2]; - (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1]; - (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0]; - } - } - } else { - Error ("%s had strange struct size", filename); - } - - if (bcPlanes != 1) { - Error ("%s was not a single plane image", filename); - } - - if (bcBitCount != 8) { - Error ("%s was not an 8 bit image", filename); - } - - if (bcHeight < 0) { - bcHeight = -bcHeight; - flipped = qtrue; - } else { - flipped = qfalse; - } - - if (width) - *width = bcWidth; - if (height) - *height = bcHeight; - - if (!pic) { - free (in); - return; - } - - out = safe_malloc ( bcWidth * bcHeight ); - *pic = out; - pos = bfOffBits; - - if (flipped) { - for (i = 0 ; i < bcHeight ; i++) { - memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth); - pos += bcWidth; - } - } else { - memcpy (out, in+pos, bcWidth*bcHeight); - pos += bcWidth*bcHeight; - } - - free (in); -} - - -/* -============================================================================ - -LOAD IMAGE - -============================================================================ -*/ - -/* -============== -Load256Image - -Will load either an lbm or pcx, depending on extension. -Any of the return pointers can be NULL if you don't want them. -============== -*/ -void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_stricmp (ext, "lbm")) - { - LoadLBM (name, pixels, palette); - if (width) - *width = bmhd.w; - if (height) - *height = bmhd.h; - } - else if (!Q_stricmp (ext, "pcx")) - { - LoadPCX (name, pixels, palette, width, height); - } - else if (!Q_stricmp (ext, "bmp")) - { - LoadBMP (name, pixels, palette, width, height); - } - else - Error ("%s doesn't have a known image extension", name); -} - - -/* -============== -Save256Image - -Will save either an lbm or pcx, depending on extension. -============== -*/ -void Save256Image (const char *name, byte *pixels, byte *palette, - int width, int height) -{ - char ext[128]; - - ExtractFileExtension (name, ext); - if (!Q_stricmp (ext, "lbm")) - { - WriteLBMfile (name, pixels, width, height, palette); - } - else if (!Q_stricmp (ext, "pcx")) - { - WritePCXfile (name, pixels, width, height, palette); - } - else - Error ("%s doesn't have a known image extension", name); -} - - - - -/* -============================================================================ - -TARGA IMAGE - -============================================================================ -*/ - -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; - -/* -============= -LoadTGABuffer -============= -*/ -void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height) -{ - int columns, rows, numPixels; - byte *pixbuf; - int row, column; - byte *buf_p; - TargaHeader targa_header; - byte *targa_rgba; - - *pic = NULL; - - buf_p = buffer; - - targa_header.id_length = *buf_p++; - targa_header.colormap_type = *buf_p++; - targa_header.image_type = *buf_p++; - - targa_header.colormap_index = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.colormap_length = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.colormap_size = *buf_p++; - targa_header.x_origin = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.y_origin = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.width = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.height = LittleShort ( *(short *)buf_p ); - buf_p += 2; - targa_header.pixel_size = *buf_p++; - targa_header.attributes = *buf_p++; - - if (targa_header.image_type!=2 - && targa_header.image_type!=10 - && targa_header.image_type != 3 ) - { - Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); - } - - if ( targa_header.colormap_type != 0 ) - { - Error("LoadTGA: colormaps not supported\n" ); - } - - if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) - { - Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); - } - - columns = targa_header.width; - rows = targa_header.height; - numPixels = columns * rows; - - if (width) - *width = columns; - if (height) - *height = rows; - - targa_rgba = safe_malloc (numPixels*4); - *pic = targa_rgba; - - if (targa_header.id_length != 0) - buf_p += targa_header.id_length; // skip TARGA image comment - - if ( targa_header.image_type==2 || targa_header.image_type == 3 ) - { - // Uncompressed RGB or gray scale image - for(row=rows-1; row>=0; row--) - { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column<columns; column++) - { - unsigned char red,green,blue,alphabyte; - switch (targa_header.pixel_size) - { - - case 8: - blue = *buf_p++; - green = blue; - red = blue; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); - break; - } - } - } - } - else if (targa_header.image_type==10) { // Runlength encoded RGB images - unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; - - red = 0; - green = 0; - blue = 0; - alphabyte = 0xff; - - for(row=rows-1; row>=0; row--) { - pixbuf = targa_rgba + row*columns*4; - for(column=0; column<columns; ) { - packetHeader= *buf_p++; - packetSize = 1 + (packetHeader & 0x7f); - if (packetHeader & 0x80) { // run-length packet - switch (targa_header.pixel_size) { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - break; - default: - //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); - break; - } - - for(j=0;j<packetSize;j++) { - *pixbuf++=red; - *pixbuf++=green; - *pixbuf++=blue; - *pixbuf++=alphabyte; - column++; - if (column==columns) { // run spans across rows - column=0; - if (row>0) - row--; - else - goto breakOut; - pixbuf = targa_rgba + row*columns*4; - } - } - } - else { // non run-length packet - for(j=0;j<packetSize;j++) { - switch (targa_header.pixel_size) { - case 24: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = 255; - break; - case 32: - blue = *buf_p++; - green = *buf_p++; - red = *buf_p++; - alphabyte = *buf_p++; - *pixbuf++ = red; - *pixbuf++ = green; - *pixbuf++ = blue; - *pixbuf++ = alphabyte; - break; - default: - //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); - break; - } - column++; - if (column==columns) { // pixel packet run spans across rows - column=0; - if (row>0) - 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<c ; i+=4) - { - buffer[i] = data[i-18+2]; // blue - buffer[i+1] = data[i-18+1]; // green - buffer[i+2] = data[i-18+0]; // red - buffer[i+3] = data[i-18+3]; // alpha - } - - f = fopen (filename, "wb"); - fwrite (buffer, 1, c, f); - fclose (f); - - free (buffer); -} - -/* -============================================================================ - -LOAD32BITIMAGE - -============================================================================ -*/ - -/* -============== -Load32BitImage - -Any of the return pointers can be NULL if you don't want them. -============== -*/ -void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height) -{ - char ext[128]; - byte *palette; - byte *pixels8; - byte *pixels32; - int size; - int i; - int v; - - ExtractFileExtension (name, ext); - if (!Q_stricmp (ext, "tga")) { - LoadTGA (name, (byte **)pixels, width, height); - } else { - Load256Image (name, &pixels8, &palette, width, height); - if (!pixels) { - return; - } - size = *width * *height; - pixels32 = safe_malloc(size * 4); - *pixels = (unsigned *)pixels32; - for (i = 0 ; i < size ; i++) { - v = pixels8[i]; - pixels32[i*4 + 0] = palette[ v * 3 + 0 ]; - pixels32[i*4 + 1] = palette[ v * 3 + 1 ]; - pixels32[i*4 + 2] = palette[ v * 3 + 2 ]; - pixels32[i*4 + 3] = 0xff; - } - } -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 (count<bpwidth); + + if (count>bpwidth) + 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 ; y<bmhd.h ; y++, pic_p += bmhd.w) + { + if (bmhd.compression == cm_rle1) + body_p = LBMRLEDecompress ((byte *)body_p + , pic_p , bmhd.w); + else if (bmhd.compression == cm_none) + { + memcpy (pic_p,body_p,bmhd.w); + body_p += Align(bmhd.w); + } + } + + } + else + { + // + // unpack ILBM + // + Error ("%s is an interlaced LBM, not packed", filename); + } + break; + } + + LBM_P += Align(chunklength); + } + + free (LBMbuffer); + + *picture = picbuffer; + + if (palette) + *palette = cmapbuffer; +} + + +/* +============================================================================ + + WRITE LBM + +============================================================================ +*/ + +/* +============== +WriteLBMfile +============== +*/ +void WriteLBMfile (const char *filename, byte *data, + int width, int height, byte *palette) +{ + byte *lbm, *lbmptr; + int *formlength, *bmhdlength, *cmaplength, *bodylength; + int length; + bmhd_t basebmhd; + + lbm = lbmptr = safe_malloc (width*height+1000); + +// +// start FORM +// + *lbmptr++ = 'F'; + *lbmptr++ = 'O'; + *lbmptr++ = 'R'; + *lbmptr++ = 'M'; + + formlength = (int*)lbmptr; + lbmptr+=4; // leave space for length + + *lbmptr++ = 'P'; + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = ' '; + +// +// write BMHD +// + *lbmptr++ = 'B'; + *lbmptr++ = 'M'; + *lbmptr++ = 'H'; + *lbmptr++ = 'D'; + + bmhdlength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memset (&basebmhd,0,sizeof(basebmhd)); + basebmhd.w = BigShort((short)width); + basebmhd.h = BigShort((short)height); + basebmhd.nPlanes = BigShort(8); + basebmhd.xAspect = BigShort(5); + basebmhd.yAspect = BigShort(6); + basebmhd.pageWidth = BigShort((short)width); + basebmhd.pageHeight = BigShort((short)height); + + memcpy (lbmptr,&basebmhd,sizeof(basebmhd)); + lbmptr += sizeof(basebmhd); + + length = lbmptr-(byte *)bmhdlength-4; + *bmhdlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write CMAP +// + *lbmptr++ = 'C'; + *lbmptr++ = 'M'; + *lbmptr++ = 'A'; + *lbmptr++ = 'P'; + + cmaplength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,palette,768); + lbmptr += 768; + + length = lbmptr-(byte *)cmaplength-4; + *cmaplength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write BODY +// + *lbmptr++ = 'B'; + *lbmptr++ = 'O'; + *lbmptr++ = 'D'; + *lbmptr++ = 'Y'; + + bodylength = (int *)lbmptr; + lbmptr+=4; // leave space for length + + memcpy (lbmptr,data,width*height); + lbmptr += width*height; + + length = lbmptr-(byte *)bodylength-4; + *bodylength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// done +// + length = lbmptr-(byte *)formlength-4; + *formlength = BigLong(length); + if (length&1) + *lbmptr++ = 0; // pad chunk to even offset + +// +// write output file +// + SaveFile (filename, lbm, lbmptr-lbm); + free (lbm); +} + + +/* +============================================================================ + +LOAD PCX + +============================================================================ +*/ + +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; + + +/* +============== +LoadPCX +============== +*/ + +/* RR2DO2 */ +#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;} + +void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height ) +{ + byte *raw; + pcx_t *pcx; + int x, y, lsize; + int len; + int dataByte, runLength; + byte *out, *pix; + + + /* load the file */ + len = vfsLoadFile (filename, (void **)&raw, 0); + if( len == -1 ) + Error( "LoadPCX: Couldn't read %s", filename ); + + + /* parse the PCX file */ + pcx = (pcx_t *)raw; + raw = &pcx->data; + + 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<height ; i++) + { + for (j=0 ; j<width ; j++) + { + if ( (*data & 0xc0) != 0xc0) + *pack++ = *data++; + else + { + *pack++ = 0xc1; + *pack++ = *data++; + } + } + } + + // write the palette + *pack++ = 0x0c; // palette ID byte + for (i=0 ; i<768 ; i++) + *pack++ = *palette++; + +// write output file + length = pack - (byte *)pcx; + SaveFile (filename, pcx, length); + + free (pcx); +} + +/* +============================================================================ + +LOAD BMP + +============================================================================ +*/ + + +/* + +// we can't just use these structures, because +// compiler structure alignment will not be portable +// on this unaligned stuff + +typedef struct tagBITMAPFILEHEADER { // bmfh + WORD bfType; // BM + DWORD bfSize; + WORD bfReserved1; + WORD bfReserved2; + DWORD bfOffBits; +} BITMAPFILEHEADER; + +typedef struct tagBITMAPINFOHEADER{ // bmih + DWORD biSize; + LONG biWidth; + LONG biHeight; + WORD biPlanes; + WORD biBitCount + DWORD biCompression; + DWORD biSizeImage; + LONG biXPelsPerMeter; + LONG biYPelsPerMeter; + DWORD biClrUsed; + DWORD biClrImportant; +} BITMAPINFOHEADER; + +typedef struct tagBITMAPINFO { // bmi + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[1]; +} BITMAPINFO; + +typedef struct tagBITMAPCOREHEADER { // bmch + DWORD bcSize; + WORD bcWidth; + WORD bcHeight; + WORD bcPlanes; + WORD bcBitCount; +} BITMAPCOREHEADER; + +typedef struct _BITMAPCOREINFO { // bmci + BITMAPCOREHEADER bmciHeader; + RGBTRIPLE bmciColors[1]; +} BITMAPCOREINFO; + +*/ + +/* +============== +LoadBMP +============== +*/ +void LoadBMP (const char *filename, byte **pic, byte **palette, int *width, int *height) +{ + byte *out; + int i; + int bfSize; + int bfOffBits; + int structSize; + int bcWidth; + int bcHeight; + int bcPlanes; + int bcBitCount; + byte bcPalette[1024]; + qboolean flipped; + byte *in; + int len, pos = 0; + + len = vfsLoadFile (filename, (void **)&in, 0); + if (len == -1) + { + Error ("Couldn't read %s", filename); + } + + i = bufLittleShort (in, len, &pos); + if (i != 'B' + ('M'<<8) ) { + Error ("%s is not a bmp file", filename); + } + + bfSize = bufLittleLong (in, len, &pos); + bufLittleShort(in, len, &pos); + bufLittleShort(in, len, &pos); + bfOffBits = bufLittleLong (in, len, &pos); + + // the size will tell us if it is a + // bitmapinfo or a bitmapcore + structSize = bufLittleLong (in, len, &pos); + if (structSize == 40) + { + // bitmapinfo + bcWidth = bufLittleLong(in, len, &pos); + bcHeight= bufLittleLong(in, len, &pos); + bcPlanes = bufLittleShort(in, len, &pos); + bcBitCount = bufLittleShort(in, len, &pos); + + pos += 24; + + if (palette) + { + memcpy (bcPalette, in+pos, 1024); + pos += 1024; + *palette = safe_malloc(768); + + for (i = 0 ; i < 256 ; i++) + { + (*palette)[i * 3 + 0] = bcPalette[i * 4 + 2]; + (*palette)[i * 3 + 1] = bcPalette[i * 4 + 1]; + (*palette)[i * 3 + 2] = bcPalette[i * 4 + 0]; + } + } + } + else if (structSize == 12) + { + // bitmapcore + bcWidth = bufLittleShort(in, len, &pos); + bcHeight= bufLittleShort(in, len, &pos); + bcPlanes = bufLittleShort(in, len, &pos); + bcBitCount = bufLittleShort(in, len, &pos); + + if (palette) + { + memcpy (bcPalette, in+pos, 768); + pos += 768; + *palette = safe_malloc(768); + + for (i = 0 ; i < 256 ; i++) { + (*palette)[i * 3 + 0] = bcPalette[i * 3 + 2]; + (*palette)[i * 3 + 1] = bcPalette[i * 3 + 1]; + (*palette)[i * 3 + 2] = bcPalette[i * 3 + 0]; + } + } + } else { + Error ("%s had strange struct size", filename); + } + + if (bcPlanes != 1) { + Error ("%s was not a single plane image", filename); + } + + if (bcBitCount != 8) { + Error ("%s was not an 8 bit image", filename); + } + + if (bcHeight < 0) { + bcHeight = -bcHeight; + flipped = qtrue; + } else { + flipped = qfalse; + } + + if (width) + *width = bcWidth; + if (height) + *height = bcHeight; + + if (!pic) { + free (in); + return; + } + + out = safe_malloc ( bcWidth * bcHeight ); + *pic = out; + pos = bfOffBits; + + if (flipped) { + for (i = 0 ; i < bcHeight ; i++) { + memcpy (out + bcWidth * (bcHeight - 1 - i), in+pos, bcWidth); + pos += bcWidth; + } + } else { + memcpy (out, in+pos, bcWidth*bcHeight); + pos += bcWidth*bcHeight; + } + + free (in); +} + + +/* +============================================================================ + +LOAD IMAGE + +============================================================================ +*/ + +/* +============== +Load256Image + +Will load either an lbm or pcx, depending on extension. +Any of the return pointers can be NULL if you don't want them. +============== +*/ +void Load256Image (const char *name, byte **pixels, byte **palette, int *width, int *height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_stricmp (ext, "lbm")) + { + LoadLBM (name, pixels, palette); + if (width) + *width = bmhd.w; + if (height) + *height = bmhd.h; + } + else if (!Q_stricmp (ext, "pcx")) + { + LoadPCX (name, pixels, palette, width, height); + } + else if (!Q_stricmp (ext, "bmp")) + { + LoadBMP (name, pixels, palette, width, height); + } + else + Error ("%s doesn't have a known image extension", name); +} + + +/* +============== +Save256Image + +Will save either an lbm or pcx, depending on extension. +============== +*/ +void Save256Image (const char *name, byte *pixels, byte *palette, + int width, int height) +{ + char ext[128]; + + ExtractFileExtension (name, ext); + if (!Q_stricmp (ext, "lbm")) + { + WriteLBMfile (name, pixels, width, height, palette); + } + else if (!Q_stricmp (ext, "pcx")) + { + WritePCXfile (name, pixels, width, height, palette); + } + else + Error ("%s doesn't have a known image extension", name); +} + + + + +/* +============================================================================ + +TARGA IMAGE + +============================================================================ +*/ + +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; + +/* +============= +LoadTGABuffer +============= +*/ +void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height) +{ + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + TargaHeader targa_header; + byte *targa_rgba; + + *pic = NULL; + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.colormap_length = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.colormap_size = *buf_p++; + targa_header.x_origin = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.y_origin = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.width = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.height = LittleShort ( *(short *)buf_p ); + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=2 + && targa_header.image_type!=10 + && targa_header.image_type != 3 ) + { + Error("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n"); + } + + if ( targa_header.colormap_type != 0 ) + { + Error("LoadTGA: colormaps not supported\n" ); + } + + if ( ( targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) && targa_header.image_type != 3 ) + { + Error("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n"); + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = safe_malloc (numPixels*4); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + if ( targa_header.image_type==2 || targa_header.image_type == 3 ) + { + // Uncompressed RGB or gray scale image + for(row=rows-1; row>=0; row--) + { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; column++) + { + unsigned char red,green,blue,alphabyte; + switch (targa_header.pixel_size) + { + + case 8: + blue = *buf_p++; + green = blue; + red = blue; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + } + } + } + else if (targa_header.image_type==10) { // Runlength encoded RGB images + unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j; + + red = 0; + green = 0; + blue = 0; + alphabyte = 0xff; + + for(row=rows-1; row>=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column<columns; ) { + packetHeader= *buf_p++; + packetSize = 1 + (packetHeader & 0x7f); + if (packetHeader & 0x80) { // run-length packet + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + break; + default: + //Error("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + + for(j=0;j<packetSize;j++) { + *pixbuf++=red; + *pixbuf++=green; + *pixbuf++=blue; + *pixbuf++=alphabyte; + column++; + if (column==columns) { // run spans across rows + column=0; + if (row>0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j<packetSize;j++) { + switch (targa_header.pixel_size) { + case 24: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = 255; + break; + case 32: + blue = *buf_p++; + green = *buf_p++; + red = *buf_p++; + alphabyte = *buf_p++; + *pixbuf++ = red; + *pixbuf++ = green; + *pixbuf++ = blue; + *pixbuf++ = alphabyte; + break; + default: + //Sysprintf("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size, name ); + break; + } + column++; + if (column==columns) { // pixel packet run spans across rows + column=0; + if (row>0) + 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<c ; i+=4) + { + buffer[i] = data[i-18+2]; // blue + buffer[i+1] = data[i-18+1]; // green + buffer[i+2] = data[i-18+0]; // red + buffer[i+3] = data[i-18+3]; // alpha + } + + f = fopen (filename, "wb"); + fwrite (buffer, 1, c, f); + fclose (f); + + free (buffer); +} + +/* +============================================================================ + +LOAD32BITIMAGE + +============================================================================ +*/ + +/* +============== +Load32BitImage + +Any of the return pointers can be NULL if you don't want them. +============== +*/ +void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height) +{ + char ext[128]; + byte *palette; + byte *pixels8; + byte *pixels32; + int size; + int i; + int v; + + ExtractFileExtension (name, ext); + if (!Q_stricmp (ext, "tga")) { + LoadTGA (name, (byte **)pixels, width, height); + } else { + Load256Image (name, &pixels8, &palette, width, height); + if (!pixels) { + return; + } + size = *width * *height; + pixels32 = safe_malloc(size * 4); + *pixels = (unsigned *)pixels32; + for (i = 0 ; i < size ; i++) { + v = pixels8[i]; + pixels32[i*4 + 0] = palette[ v * 3 + 0 ]; + pixels32[i*4 + 1] = palette[ v * 3 + 1 ]; + pixels32[i*4 + 2] = palette[ v * 3 + 2 ]; + pixels32[i*4 + 3] = 0xff; + } + } +} + + diff --git a/tools/quake3/common/imagelib.h b/tools/quake3/common/imagelib.h index 46b4ae3a..e3d64e96 100644 --- a/tools/quake3/common/imagelib.h +++ b/tools/quake3/common/imagelib.h @@ -1,44 +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 -*/ - -// piclib.h - - -void LoadLBM (const char *filename, byte **picture, byte **palette); -void WriteLBMfile (const char *filename, byte *data, int width, int height - , byte *palette); -void LoadPCX (const char *filename, byte **picture, byte **palette, int *width, int *height); -void WritePCXfile (const char *filename, byte *data, int width, int height - , byte *palette); - -// loads / saves either lbm or pcx, depending on extension -void Load256Image (const char *name, byte **pixels, byte **palette, - int *width, int *height); -void Save256Image (const char *name, byte *pixels, byte *palette, - int width, int height); - - -void LoadTGA (const char *filename, byte **pixels, int *width, int *height); -void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height); -void WriteTGA (const char *filename, byte *data, int width, int height); - -void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 (const char *filename, byte **picture, byte **palette); +void WriteLBMfile (const char *filename, byte *data, int width, int height + , byte *palette); +void LoadPCX (const char *filename, byte **picture, byte **palette, int *width, int *height); +void WritePCXfile (const char *filename, byte *data, int width, int height + , byte *palette); + +// loads / saves either lbm or pcx, depending on extension +void Load256Image (const char *name, byte **pixels, byte **palette, + int *width, int *height); +void Save256Image (const char *name, byte *pixels, byte *palette, + int width, int height); + + +void LoadTGA (const char *filename, byte **pixels, int *width, int *height); +void LoadTGABuffer ( byte *buffer, byte **pic, int *width, int *height); +void WriteTGA (const char *filename, byte *data, int width, int height); + +void Load32BitImage (const char *name, unsigned **pixels, int *width, int *height); + diff --git a/tools/quake3/common/inout.c b/tools/quake3/common/inout.c index ede88891..dcdd0893 100644 --- a/tools/quake3/common/inout.c +++ b/tools/quake3/common/inout.c @@ -1,367 +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 <sys/types.h> -#include <sys/stat.h> - -#ifdef _WIN32 -#include <direct.h> -#include <windows.h> -#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); - 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 level='flag'> - message string - .. various nodes to describe corresponding geometry .. - </message> - */ - 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#include <windows.h> +#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, "<?xml version=\"1.0\"?><q3map_feedback version=\"" Q3MAP_STREAM_VERSION "\">"); + 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 level='flag'> + message string + .. various nodes to describe corresponding geometry .. + </message> + */ + 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 index b7f13270..d417a583 100644 --- a/tools/quake3/common/inout.h +++ b/tools/quake3/common/inout.h @@ -1,61 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index eb67e065..0620f9b4 100644 --- a/tools/quake3/common/l3dslib.c +++ b/tools/quake3/common/l3dslib.c @@ -1,301 +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 <stdio.h> -#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<numtris ; i++) - { - for (j=0 ; j<3 ; j++) - { - for (k=0 ; k<3 ; k++) - { - ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; - } - } - } - - totaltris += numtris; - numtris = 0; - vertsfound = 0; - trisfound = 0; -} - - -int ParseVertexL (FILE *input) -{ - int i, j, startbytesread, numverts; - unsigned short tshort; - - if (vertsfound) - Error ("Error: Multiple vertex chunks"); - - vertsfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numverts = (int)tshort; - - if (numverts > MAXVERTS) - Error ("Error: Too many vertices"); - - for (i=0 ; i<numverts ; i++) - { - for (j=0 ; j<3 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&fverts[i][j], sizeof(float), 1, input); - bytesread += sizeof(float); - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseFaceL1 (FILE *input) -{ - - int i, j, startbytesread; - unsigned short tshort; - - if (trisfound) - Error ("Error: Multiple face chunks"); - - trisfound = 1; - startbytesread = bytesread; - - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - numtris = (int)tshort; - - if (numtris > MAXTRIANGLES) - Error ("Error: Too many triangles"); - - for (i=0 ; i<numtris ; i++) - { - for (j=0 ; j<4 ; j++) - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&tshort, sizeof(tshort), 1, input); - bytesread += sizeof(tshort); - tris[i].v[j] = (int)tshort; - } - } - - if (vertsfound && trisfound) - StoreAliasTriangles (); - - return bytesread - startbytesread; -} - - -int ParseChunk (FILE *input) -{ -#define BLOCK_SIZE 4096 - char temp[BLOCK_SIZE]; - unsigned short type; - int i, length, w, t, retval; - - level++; - retval = 0; - -// chunk type - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread(&type, sizeof(type), 1, input); - bytesread += sizeof(type); - -// chunk length - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&length, sizeof(length), 1, input); - bytesread += sizeof(length); - w = length - 6; - -// process chunk if we care about it, otherwise skip it - switch (type) - { - case TRI_VERTEXL: - w -= ParseVertexL (input); - goto ParseSubchunk; - - case TRI_FACEL1: - w -= ParseFaceL1 (input); - goto ParseSubchunk; - - case EDIT_OBJECT: - // read the name - i = 0; - - do - { - if (feof(input)) - Error ("Error: unexpected end of file"); - - fread (&temp[i], 1, 1, input); - i++; - w--; - bytesread++; - } while (temp[i-1]); - - case MAIN3DS: - case OBJ_TRIMESH: - case EDIT3DS: - // parse through subchunks -ParseSubchunk: - while (w > 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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<numtris ; i++) + { + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; + } + } + } + + totaltris += numtris; + numtris = 0; + vertsfound = 0; + trisfound = 0; +} + + +int ParseVertexL (FILE *input) +{ + int i, j, startbytesread, numverts; + unsigned short tshort; + + if (vertsfound) + Error ("Error: Multiple vertex chunks"); + + vertsfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numverts = (int)tshort; + + if (numverts > MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i<numverts ; i++) + { + for (j=0 ; j<3 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&fverts[i][j], sizeof(float), 1, input); + bytesread += sizeof(float); + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseFaceL1 (FILE *input) +{ + + int i, j, startbytesread; + unsigned short tshort; + + if (trisfound) + Error ("Error: Multiple face chunks"); + + trisfound = 1; + startbytesread = bytesread; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + numtris = (int)tshort; + + if (numtris > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i<numtris ; i++) + { + for (j=0 ; j<4 ; j++) + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&tshort, sizeof(tshort), 1, input); + bytesread += sizeof(tshort); + tris[i].v[j] = (int)tshort; + } + } + + if (vertsfound && trisfound) + StoreAliasTriangles (); + + return bytesread - startbytesread; +} + + +int ParseChunk (FILE *input) +{ +#define BLOCK_SIZE 4096 + char temp[BLOCK_SIZE]; + unsigned short type; + int i, length, w, t, retval; + + level++; + retval = 0; + +// chunk type + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread(&type, sizeof(type), 1, input); + bytesread += sizeof(type); + +// chunk length + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&length, sizeof(length), 1, input); + bytesread += sizeof(length); + w = length - 6; + +// process chunk if we care about it, otherwise skip it + switch (type) + { + case TRI_VERTEXL: + w -= ParseVertexL (input); + goto ParseSubchunk; + + case TRI_FACEL1: + w -= ParseFaceL1 (input); + goto ParseSubchunk; + + case EDIT_OBJECT: + // read the name + i = 0; + + do + { + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp[i], 1, 1, input); + i++; + w--; + bytesread++; + } while (temp[i-1]); + + case MAIN3DS: + case OBJ_TRIMESH: + case EDIT3DS: + // parse through subchunks +ParseSubchunk: + while (w > 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 index a22d9c87..ae835963 100644 --- a/tools/quake3/common/l3dslib.h +++ b/tools/quake3/common/l3dslib.h @@ -1,26 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/mutex.c b/tools/quake3/common/mutex.c index bd699bf9..f7be7f5f 100644 --- a/tools/quake3/common/mutex.c +++ b/tools/quake3/common/mutex.c @@ -1,197 +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 <windows.h> - -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 <pthread.h> - -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 <task.h> -#include <abi_mutex.h> -#include <sys/types.h> -#include <sys/prctl.h> - -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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <windows.h> + +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 <pthread.h> + +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 <task.h> +#include <abi_mutex.h> +#include <sys/types.h> +#include <sys/prctl.h> + +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 index ce6dab00..1bd34dc6 100644 --- a/tools/quake3/common/mutex.h +++ b/tools/quake3/common/mutex.h @@ -1,28 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 9f5a1d49..187b1e70 100644 --- a/tools/quake3/common/polylib.c +++ b/tools/quake3/common/polylib.c @@ -1,745 +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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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) ); -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<in->numpoints ; 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 ; i<w->numpoints ; 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 ; j<w->numpoints ; 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 ; i<w->numpoints ; 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 index 0bc4a8ad..58b21d5a 100644 --- a/tools/quake3/common/polylib.h +++ b/tools/quake3/common/polylib.h @@ -1,57 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 459fde12..04a4d5b7 100644 --- a/tools/quake3/common/polyset.h +++ b/tools/quake3/common/polyset.h @@ -1,51 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 584d8e96..091640ed 100644 --- a/tools/quake3/common/qfiles.h +++ b/tools/quake3/common/qfiles.h @@ -1,489 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index eeeac14f..25bacca4 100644 --- a/tools/quake3/common/qthreads.h +++ b/tools/quake3/common/qthreads.h @@ -1,31 +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); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 267078c6..a4c9bb88 100644 --- a/tools/quake3/common/scriplib.c +++ b/tools/quake3/common/scriplib.c @@ -1,409 +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"); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index accc5a1c..e924e974 100644 --- a/tools/quake3/common/scriplib.h +++ b/tools/quake3/common/scriplib.h @@ -1,55 +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); +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index cb8f045c..425e4f28 100644 --- a/tools/quake3/common/surfaceflags.h +++ b/tools/quake3/common/surfaceflags.h @@ -1,112 +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 - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 49ded171..463d32bd 100644 --- a/tools/quake3/common/threads.c +++ b/tools/quake3/common/threads.c @@ -1,620 +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 <pthread.h> -#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 <windows.h> - -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<numthreads ; i++) - { - threadhandle[i] = CreateThread( - NULL, // LPSECURITY_ATTRIBUTES lpsa, - //0, // DWORD cbStack, - - /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ - (4096 * 1024), - - (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, - (LPVOID)i, // LPVOID lpvThreadParm, - 0, // DWORD fdwCreate, - &threadid[i]); - } - - for (i=0 ; i<numthreads ; i++) - WaitForSingleObject (threadhandle[i], INFINITE); - } - DeleteCriticalSection (&crit); - - threaded = qfalse; - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -OSF1 - -=================================================================== -*/ - -#ifdef __osf__ -#define USED - -int numthreads = 4; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - numthreads = 4; - } -} - - -#include <pthread.h> - -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<numthreads ; i++) - { - if (pthread_create(&work_threads[i], attrib - , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) - Error ("pthread_create failed"); - } - - for (i=0 ; i<numthreads ; i++) - { - if (pthread_join (work_threads[i], &status) == -1) - Error ("pthread_join failed"); - } - - threaded = qfalse; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - -/* -=================================================================== - -IRIX - -=================================================================== -*/ - -#ifdef _MIPS_ISA -#define USED - -#include <task.h> -#include <abi_mutex.h> -#include <sys/types.h> -#include <sys/prctl.h> - - -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<numthreads-1 ; i++) - { - pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i - , NULL, 0x200000); // 2 meg stacks - if (pid[i] == -1) - { - perror ("sproc"); - Error ("sproc failed"); - } - } - - func(i); - - for (i=0 ; i<numthreads-1 ; i++) - wait (NULL); - - threaded = qfalse; - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - - -#endif - - -/* -======================================================================= - - Linux pthreads - -======================================================================= -*/ - -#ifdef __linux__ -#define USED - -int numthreads = 4; - -void ThreadSetDefault (void) -{ - if (numthreads == -1) // not set manually - { - /* default to one thread, only multi-thread when specifically told to */ - numthreads = 1; - } - if(numthreads > 1) - Sys_Printf("threads: %d\n", numthreads); -} - -#include <pthread.h> - -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<numthreads ; i++) - { - /* Default pthread attributes: joinable & non-realtime scheduling */ - if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) - Error("pthread_create failed"); - } - for (i=0 ; i<numthreads ; i++) - { - if(pthread_join(work_threads[i], (void **)&status) != 0) - Error("pthread_join failed"); - } - pthread_mutexattr_destroy(&mattrib); - threaded = qfalse; - } - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} -#endif // ifdef __linux__ - - -/* -======================================================================= - - SINGLE THREAD - -======================================================================= -*/ - -#ifndef USED - -int numthreads = 1; - -void ThreadSetDefault (void) -{ - numthreads = 1; -} - -void ThreadLock (void) -{ -} - -void ThreadUnlock (void) -{ -} - -/* -============= -RunThreadsOn -============= -*/ -void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) -{ - int i; - int start, end; - - dispatch = 0; - workcount = workcnt; - oldf = -1; - pacifier = showpacifier; - start = I_FloatTime (); - func(0); - - end = I_FloatTime (); - if (pacifier) - Sys_Printf (" (%i)\n", end-start); -} - -#endif +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <pthread.h> +#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 <windows.h> + +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<numthreads ; i++) + { + threadhandle[i] = CreateThread( + NULL, // LPSECURITY_ATTRIBUTES lpsa, + //0, // DWORD cbStack, + + /* ydnar: cranking stack size to eliminate radiosity crash with 1MB stack on win32 */ + (4096 * 1024), + + (LPTHREAD_START_ROUTINE)func, // LPTHREAD_START_ROUTINE lpStartAddr, + (LPVOID)i, // LPVOID lpvThreadParm, + 0, // DWORD fdwCreate, + &threadid[i]); + } + + for (i=0 ; i<numthreads ; i++) + WaitForSingleObject (threadhandle[i], INFINITE); + } + DeleteCriticalSection (&crit); + + threaded = qfalse; + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +OSF1 + +=================================================================== +*/ + +#ifdef __osf__ +#define USED + +int numthreads = 4; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + numthreads = 4; + } +} + + +#include <pthread.h> + +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<numthreads ; i++) + { + if (pthread_create(&work_threads[i], attrib + , (pthread_startroutine_t)func, (pthread_addr_t)i) == -1) + Error ("pthread_create failed"); + } + + for (i=0 ; i<numthreads ; i++) + { + if (pthread_join (work_threads[i], &status) == -1) + Error ("pthread_join failed"); + } + + threaded = qfalse; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + +/* +=================================================================== + +IRIX + +=================================================================== +*/ + +#ifdef _MIPS_ISA +#define USED + +#include <task.h> +#include <abi_mutex.h> +#include <sys/types.h> +#include <sys/prctl.h> + + +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<numthreads-1 ; i++) + { + pid[i] = sprocsp ( (void (*)(void *, size_t))func, PR_SALL, (void *)i + , NULL, 0x200000); // 2 meg stacks + if (pid[i] == -1) + { + perror ("sproc"); + Error ("sproc failed"); + } + } + + func(i); + + for (i=0 ; i<numthreads-1 ; i++) + wait (NULL); + + threaded = qfalse; + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + + +#endif + + +/* +======================================================================= + + Linux pthreads + +======================================================================= +*/ + +#ifdef __linux__ +#define USED + +int numthreads = 4; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) // not set manually + { + /* default to one thread, only multi-thread when specifically told to */ + numthreads = 1; + } + if(numthreads > 1) + Sys_Printf("threads: %d\n", numthreads); +} + +#include <pthread.h> + +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<numthreads ; i++) + { + /* Default pthread attributes: joinable & non-realtime scheduling */ + if(pthread_create(&work_threads[i], NULL, (void*)func, (void*)i) != 0) + Error("pthread_create failed"); + } + for (i=0 ; i<numthreads ; i++) + { + if(pthread_join(work_threads[i], (void **)&status) != 0) + Error("pthread_join failed"); + } + pthread_mutexattr_destroy(&mattrib); + threaded = qfalse; + } + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} +#endif // ifdef __linux__ + + +/* +======================================================================= + + SINGLE THREAD + +======================================================================= +*/ + +#ifndef USED + +int numthreads = 1; + +void ThreadSetDefault (void) +{ + numthreads = 1; +} + +void ThreadLock (void) +{ +} + +void ThreadUnlock (void) +{ +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int start, end; + + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + start = I_FloatTime (); + func(0); + + end = I_FloatTime (); + if (pacifier) + Sys_Printf (" (%i)\n", end-start); +} + +#endif diff --git a/tools/quake3/common/trilib.c b/tools/quake3/common/trilib.c index 89978949..9726569e 100644 --- a/tools/quake3/common/trilib.c +++ b/tools/quake3/common/trilib.c @@ -1,235 +1,235 @@ -/* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. - -This file is part of GtkRadiant. - -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General 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 <stdio.h> -#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 ; i<sizeof(tf_triangle)/4 ; i++) - { - ((int *)tri)[i] = BigLong (((int *)tri)[i]); - } -} - -static void ReadPolysetGeometry( triangle_t *tripool, FILE *input, int count, triangle_t *ptri ) -{ - tf_triangle tri; - int i; - - for (i = 0; i < count; ++i) { - int j; - - fread( &tri, sizeof(tf_triangle), 1, input ); - ByteSwapTri (&tri); - for (j=0 ; j<3 ; j++) - { - int k; - - for (k=0 ; k<3 ; k++) - { - ptri->verts[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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdio.h> +#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 ; i<sizeof(tf_triangle)/4 ; i++) + { + ((int *)tri)[i] = BigLong (((int *)tri)[i]); + } +} + +static void ReadPolysetGeometry( triangle_t *tripool, FILE *input, int count, triangle_t *ptri ) +{ + tf_triangle tri; + int i; + + for (i = 0; i < count; ++i) { + int j; + + fread( &tri, sizeof(tf_triangle), 1, input ); + ByteSwapTri (&tri); + for (j=0 ; j<3 ; j++) + { + int k; + + for (k=0 ; k<3 ; k++) + { + ptri->verts[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 index 0b41d3c0..30b10837 100644 --- a/tools/quake3/common/trilib.h +++ b/tools/quake3/common/trilib.h @@ -1,26 +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 ); - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 1732626a..1949db22 100644 --- a/tools/quake3/common/unzip.c +++ b/tools/quake3/common/unzip.c @@ -1,4596 +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 <stdlib.h> -#include <stdio.h> -#include <string.h> -#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 (c1<c2) - return -1; - if (c1>c2) - 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 (uBackRead<uMaxBack) - { - uLong uReadSize,uReadPos ; - int i; - if (uBackRead+BUFREADCOMMENT>uMaxBack) - 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_pos<us.offset_central_dir+us.size_central_dir) && - (err==UNZ_OK)) - err=UNZ_BADZIPFILE; - - if (err!=UNZ_OK) - { - fclose(fin); - return NULL; - } - - us.file=fin; - us.byte_before_the_zipfile = central_pos - - (us.offset_central_dir+us.size_central_dir); - us.central_pos = central_pos; - us.pfile_in_zip_read = NULL; - - - s=(unz_s*)safe_malloc(sizeof(unz_s)); - *s=us; -// unzGoToFirstFile((unzFile)s); - return (unzFile)s; -} - - -/* - Close a ZipFile opened with unzipOpen. - If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), - these files MUST be closed with unzipCloseCurrentFile before call unzipClose. - return UNZ_OK if there is no problem. */ -extern int unzClose (unzFile file) -{ - unz_s* s; - if (file==NULL) - return UNZ_PARAMERROR; - s=(unz_s*)file; - - if (s->pfile_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_filename<fileNameBufferSize) - { - *(szFileName+file_info.size_filename)='\0'; - uSizeRead = file_info.size_filename; - } - else - uSizeRead = fileNameBufferSize; - - if ((file_info.size_filename>0) && (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_extra<extraFieldBufferSize) - uSizeRead = file_info.size_file_extra; - else - uSizeRead = extraFieldBufferSize; - - if (lSeek!=0) - if (fseek(s->file,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_comment<commentBufferSize) - { - *(szComment+file_info.size_file_comment)='\0'; - uSizeRead = file_info.size_file_comment; - } - else - uSizeRead = commentBufferSize; - - if (lSeek!=0) - if (fseek(s->file,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_compressed<uReadThis) - uReadThis = (uInt)pfile_in_zip_read_info->rest_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;i<uDoCopy;i++) - *(pfile_in_zip_read_info->stream.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)<<k;k+=8;}} -#define DUMPBITS(j) {b>>=(j);k-=(j);} -/* output bytes */ -#define WAVAIL (uInt)(q<s->read?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)<<k;k+=8;}} -#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>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<<z->state->wbits)) - { - length = (1<<z->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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <stdlib.h> +#include <stdio.h> +#include <string.h> +#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 (c1<c2) + return -1; + if (c1>c2) + 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 (uBackRead<uMaxBack) + { + uLong uReadSize,uReadPos ; + int i; + if (uBackRead+BUFREADCOMMENT>uMaxBack) + 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_pos<us.offset_central_dir+us.size_central_dir) && + (err==UNZ_OK)) + err=UNZ_BADZIPFILE; + + if (err!=UNZ_OK) + { + fclose(fin); + return NULL; + } + + us.file=fin; + us.byte_before_the_zipfile = central_pos - + (us.offset_central_dir+us.size_central_dir); + us.central_pos = central_pos; + us.pfile_in_zip_read = NULL; + + + s=(unz_s*)safe_malloc(sizeof(unz_s)); + *s=us; +// unzGoToFirstFile((unzFile)s); + return (unzFile)s; +} + + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzipOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ +extern int unzClose (unzFile file) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + if (s->pfile_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_filename<fileNameBufferSize) + { + *(szFileName+file_info.size_filename)='\0'; + uSizeRead = file_info.size_filename; + } + else + uSizeRead = fileNameBufferSize; + + if ((file_info.size_filename>0) && (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_extra<extraFieldBufferSize) + uSizeRead = file_info.size_file_extra; + else + uSizeRead = extraFieldBufferSize; + + if (lSeek!=0) + if (fseek(s->file,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_comment<commentBufferSize) + { + *(szComment+file_info.size_file_comment)='\0'; + uSizeRead = file_info.size_file_comment; + } + else + uSizeRead = commentBufferSize; + + if (lSeek!=0) + if (fseek(s->file,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_compressed<uReadThis) + uReadThis = (uInt)pfile_in_zip_read_info->rest_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;i<uDoCopy;i++) + *(pfile_in_zip_read_info->stream.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)<<k;k+=8;}} +#define DUMPBITS(j) {b>>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(q<s->read?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)<<k;k+=8;}} +#define UNGRAB {c=z->avail_in-n;c=(k>>3)<c?k>>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<<z->state->wbits)) + { + length = (1<<z->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 index ddb7820a..d2ba6532 100644 --- a/tools/quake3/common/unzip.h +++ b/tools/quake3/common/unzip.h @@ -1,321 +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 -*/ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 2d2ab138..3afb00c6 100644 --- a/tools/quake3/common/vfs.c +++ b/tools/quake3/common/vfs.c @@ -1,365 +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 <stdio.h> - -#if defined (__linux__) || defined (__APPLE__) -#include <dirent.h> -#include <unistd.h> -#else -#include <wtypes.h> -#include <io.h> -#define R_OK 04 -#define S_ISDIR(mode) (mode & _S_IFDIR) -#define PATH_MAX 260 -#endif - -#include <string.h> -#include <stdlib.h> -#include <sys/stat.h> - -#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; -} +/* +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 <stdio.h> + +#if defined (__linux__) || defined (__APPLE__) +#include <dirent.h> +#include <unistd.h> +#else +#include <wtypes.h> +#include <io.h> +#define R_OK 04 +#define S_ISDIR(mode) (mode & _S_IFDIR) +#define PATH_MAX 260 +#endif + +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> + +#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 index ed74161e..44b3ffad 100644 --- a/tools/quake3/common/vfs.h +++ b/tools/quake3/common/vfs.h @@ -1,41 +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_ +/* +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/3dslib.c b/tools/quake3/q3data/3dslib.c index d5e864fd..719a487f 100644 --- a/tools/quake3/q3data/3dslib.c +++ b/tools/quake3/q3data/3dslib.c @@ -1,630 +1,630 @@ -#include <assert.h> -#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; -} +#include <assert.h> +#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 index 96757234..cd73cb43 100644 --- a/tools/quake3/q3data/3dslib.h +++ b/tools/quake3/q3data/3dslib.h @@ -1,118 +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 ); +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 index ede2a95e..af9669ab 100644 --- a/tools/quake3/q3data/compress.c +++ b/tools/quake3/q3data/compress.c @@ -1,750 +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<in.count ; i++) - { - b = in.data[i]; - code = index[b]; - *out_p++ = code; - - // shuffle b indexes to 0 - for (j=0 ; j<256 ; j++) - if (index[j] < code) - index[j]++; - index[b] = 0; - } - - out.count = out_p - out.data; - - return out; -} - - -//========================================================================== - -int bwt_size; -byte *bwt_data; - -int bwtCompare (const void *elem1, const void *elem2) -{ - int i; - int i1, i2; - int b1, b2; - - i1 = *(int *)elem1; - i2 = *(int *)elem2; - - for (i=0 ; i<bwt_size ; i++) - { - b1 = bwt_data[i1]; - b2 = bwt_data[i2]; - if (b1 < b2) - return -1; - if (b1 > 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<in.count ; i++) - sorted[i] = i; - qsort (sorted, in.count, sizeof(*sorted), bwtCompare); - - out_p = out.data = malloc(in.count + 8); - - // 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 head index - for (i=0 ; i<in.count ; i++) - if (sorted[i] == 0) - break; - *out_p++ = i&255; - *out_p++ = (i>>8)&255; - *out_p++ = (i>>16)&255; - *out_p++ = (i>>24)&255; - - // write the L column - for (i=0 ; i<in.count ; i++) - *out_p++ = in.data[(sorted[i]+in.count-1)%in.count]; - - free (sorted); - - out.count = out_p - out.data; - - return out; -} - -//========================================================================== - -typedef struct hnode_s -{ - int count; - qboolean used; - int children[2]; -} hnode_t; - -int numhnodes; -hnode_t hnodes[512]; -unsigned charbits[256]; -int charbitscount[256]; - -int SmallestNode (void) -{ - 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; -} - -void BuildChars (int nodenum, unsigned bits, int bitcount) -{ - hnode_t *node; - - if (nodenum < 256) - { - if (bitcount > 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<in.count ; i++) - hnodes[in.data[i]].count++; - - // normalize counts - max = 0; - maxchar = 0; - for (i=0 ; i<256 ; i++) - { - if (hnodes[i].count > 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<in.count ; i++) - { - c = charbitscount[in.data[i]]; - bits = charbits[in.data[i]]; - while (c) - { - c--; - if (bits & (1<<c)) - out_p[outbits>>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<in.count ; ) - { - val = in.data[i]; - rle_bytes[val]++; - repeat = 1; - i++; - while (i<in.count && repeat < 255 && in.data[i] == val) - { - repeat++; - i++; - } -if (repeat < 256) -rle_counts[repeat]++; - if (repeat > 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 ; ) - { - val = in.data[i]; -#if 1 -// chained search - bestlength = 0; - beststart = 0; - - max = FRONT_WINDOW; - if (i + max > in.count) - max = in.count - i; - - start = lzss_head[val]; - while (start != -1 && start >= i-BACK_WINDOW) - { - // count match length - for (j=0 ; j<max ; j++) - if (in.data[start+j] != in.data[i+j]) - break; - if (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<max ; j++) - if (in.data[start+j] != in.data[i+j]) - break; - if (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<<j) ) - out_p[outbits>>3] |= 1<<(outbits&7); - } - else - { // output a phrase - outbits++; // leave a 0 bit to mark phrase - for (j=0 ; j<BACK_BITS ; j++, outbits++) - if (beststart & (1<<j) ) - out_p[outbits>>3] |= 1<<(outbits&7); - for (j=0 ; j<FRONT_BITS ; j++, outbits++) - if (bestlength & (1<<j) ) - out_p[outbits>>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<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; -} - - -/* -================== -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); -} - - -/* -================== -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; -#if 1 - 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; - } -#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<HUF_TOKENS ; j++) - { - if (hnodes1[i][j].count > max) - max = hnodes1[i][j].count; - } - if (max == 0) - max = 1; - total = 0; - for (j=0 ; j<HUF_TOKENS ; j++) - { // easy to overflow 32 bits here! - 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); - } - -#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<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; -#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<<c)) - out_p[outbits>>3] |= 1<<(outbits&7); - outbits++; - } - i += rept-1; - } -#endif - } - - out_p += (outbits+7)>>3; - - out.count = out_p - out.data; - - return out; -} - -#endif +#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<in.count ; i++) + { + b = in.data[i]; + code = index[b]; + *out_p++ = code; + + // shuffle b indexes to 0 + for (j=0 ; j<256 ; j++) + if (index[j] < code) + index[j]++; + index[b] = 0; + } + + out.count = out_p - out.data; + + return out; +} + + +//========================================================================== + +int bwt_size; +byte *bwt_data; + +int bwtCompare (const void *elem1, const void *elem2) +{ + int i; + int i1, i2; + int b1, b2; + + i1 = *(int *)elem1; + i2 = *(int *)elem2; + + for (i=0 ; i<bwt_size ; i++) + { + b1 = bwt_data[i1]; + b2 = bwt_data[i2]; + if (b1 < b2) + return -1; + if (b1 > 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<in.count ; i++) + sorted[i] = i; + qsort (sorted, in.count, sizeof(*sorted), bwtCompare); + + out_p = out.data = malloc(in.count + 8); + + // 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 head index + for (i=0 ; i<in.count ; i++) + if (sorted[i] == 0) + break; + *out_p++ = i&255; + *out_p++ = (i>>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i<in.count ; i++) + *out_p++ = in.data[(sorted[i]+in.count-1)%in.count]; + + free (sorted); + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + +typedef struct hnode_s +{ + int count; + qboolean used; + int children[2]; +} hnode_t; + +int numhnodes; +hnode_t hnodes[512]; +unsigned charbits[256]; +int charbitscount[256]; + +int SmallestNode (void) +{ + 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; +} + +void BuildChars (int nodenum, unsigned bits, int bitcount) +{ + hnode_t *node; + + if (nodenum < 256) + { + if (bitcount > 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<in.count ; i++) + hnodes[in.data[i]].count++; + + // normalize counts + max = 0; + maxchar = 0; + for (i=0 ; i<256 ; i++) + { + if (hnodes[i].count > 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<in.count ; i++) + { + c = charbitscount[in.data[i]]; + bits = charbits[in.data[i]]; + while (c) + { + c--; + if (bits & (1<<c)) + out_p[outbits>>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<in.count ; ) + { + val = in.data[i]; + rle_bytes[val]++; + repeat = 1; + i++; + while (i<in.count && repeat < 255 && in.data[i] == val) + { + repeat++; + i++; + } +if (repeat < 256) +rle_counts[repeat]++; + if (repeat > 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 ; ) + { + val = in.data[i]; +#if 1 +// chained search + bestlength = 0; + beststart = 0; + + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j<max ; j++) + if (in.data[start+j] != in.data[i+j]) + break; + if (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<max ; j++) + if (in.data[start+j] != in.data[i+j]) + break; + if (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<<j) ) + out_p[outbits>>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j<BACK_BITS ; j++, outbits++) + if (beststart & (1<<j) ) + out_p[outbits>>3] |= 1<<(outbits&7); + for (j=0 ; j<FRONT_BITS ; j++, outbits++) + if (bestlength & (1<<j) ) + out_p[outbits>>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<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; +} + + +/* +================== +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); +} + + +/* +================== +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; +#if 1 + 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; + } +#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<HUF_TOKENS ; j++) + { + if (hnodes1[i][j].count > max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; + for (j=0 ; j<HUF_TOKENS ; j++) + { // easy to overflow 32 bits here! + 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); + } + +#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<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; +#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<<c)) + out_p[outbits>>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 index ea661754..de872d2b 100644 --- a/tools/quake3/q3data/images.c +++ b/tools/quake3/q3data/images.c @@ -1,465 +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 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, w, h, lbmpalette); - - free (cropped); -} - -/* -============== -Cmd_Raw - -$grab filename x y width height -============== -*/ -void Cmd_Raw (void) -{ - int xl,yl,w,h,y; - byte *cropped; - char savename[1024]; - char dest[1024]; - - GetToken (qfalse); - - sprintf (savename, "%s%s.lmp", writedir, token); - - if (g_release) - { - sprintf (dest, "%s.lmp", 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 ; y<h ; y++) - { - memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); - } - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - - SaveFile (savename, cropped, w*h); - - free (cropped); -} - -/* -============================================================================= - -COLORMAP GRABBING - -============================================================================= -*/ - -/* -=============== -BestColor -=============== -*/ -byte BestColor (int r, int g, int b, int start, int stop) -{ - int i; - int dr, dg, db; - int bestdistortion, distortion; - int bestcolor; - byte *pal; - -// -// let any color go to 0 as a last resort -// - bestdistortion = 256*256*4; - bestcolor = 0; - - pal = colormap_palette + start*3; - for (i=start ; i<= stop ; i++) - { - dr = r - (int)pal[0]; - dg = g - (int)pal[1]; - db = b - (int)pal[2]; - pal += 3; - distortion = dr*dr + dg*dg + db*db; - if (distortion < bestdistortion) - { - if (!distortion) - return i; // perfect match - - bestdistortion = distortion; - bestcolor = i; - } - } - - return bestcolor; -} - - -/* -============== -Cmd_Colormap - -$colormap filename - - the brightes colormap is first in the table (FIXME: reverse this now?) - - 64 rows of 256 : lightmaps - 256 rows of 256 : translucency table -============== -*/ -void Cmd_Colormap (void) -{ - int levels, brights; - int l, c; - float frac, red, green, blue; - float range; - byte *cropped, *lump_p; - char savename[1024]; - char dest[1024]; - - colormap_issued = qtrue; - if (!g_release) - memcpy (colormap_palette, lbmpalette, 768); - - if (!TokenAvailable ()) - { // just setting colormap_issued - return; - } - - GetToken (qfalse); - sprintf (savename, "%spics/%s.pcx", writedir, token); - - if (g_release) - { - sprintf (dest, "pics/%s.pcx", token); - ReleaseFile (dest); - return; - } - - range = 2; - levels = 64; - brights = 1; // ignore 255 (transparent) - - cropped = malloc((levels+256)*256); - lump_p = cropped; - -// shaded levels - for (l=0;l<levels;l++) - { - frac = range - range*(float)l/(levels-1); - for (c=0 ; c<256-brights ; c++) - { - red = lbmpalette[c*3]; - green = lbmpalette[c*3+1]; - blue = lbmpalette[c*3+2]; - - red = (int)(red*frac+0.5); - green = (int)(green*frac+0.5); - blue = (int)(blue*frac+0.5); - -// -// note: 254 instead of 255 because 255 is the transparent color, and we -// don't want anything remapping to that -// don't use color 0, because NT can't remap that (or 255) -// - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - - // fullbrights allways stay the same - for ( ; c<256 ; c++) - *lump_p++ = c; - } - -// 66% transparancy table - for (l=0;l<255;l++) - { - for (c=0 ; c<255 ; c++) - { - red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; - green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; - blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; - - *lump_p++ = BestColor(red,green,blue, 1, 254); - } - *lump_p++ = 255; - } - for (c=0 ; c<256 ; c++) - *lump_p++ = 255; - - // save off the new image - printf ("saving %s\n", savename); - CreatePath (savename); - WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); - - free (cropped); -} - -/* -============================================================================= - -MIPTEX GRABBING - -============================================================================= -*/ - -byte pixdata[256]; - -int d_red, d_green, d_blue; - -byte palmap[32][32][32]; -qboolean palmap_built; - -/* -============= -FindColor -============= -*/ -int FindColor (int r, int g, int b) -{ - int bestcolor; - - if (r > 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<count ; i++) - { - pix = pixdata[i]; - - r += lbmpalette[pix*3]; - g += lbmpalette[pix*3+1]; - b += lbmpalette[pix*3+2]; - vis++; - } - - r /= vis; - g /= vis; - b /= vis; - - // error diffusion - r += d_red; - g += d_green; - b += d_blue; - -// -// find the best color -// - bestcolor = FindColor (r, g, b); - - // error diffusion - pal = colormap_palette + bestcolor*3; - d_red = r - (int)pal[0]; - d_green = g - (int)pal[1]; - d_blue = b - (int)pal[2]; - - return bestcolor; -} - - - -/* -============================================================================= - -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; - - GetToken (qfalse); - - 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", writedir, token, suf[i]); - if (FileTime (name) != -1) - printf ("%s already exists, not overwriting.\n", name); - else - WritePCXfile (name, image, 256, 256, colormap_palette); - } -} - +#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 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, w, h, lbmpalette); + + free (cropped); +} + +/* +============== +Cmd_Raw + +$grab filename x y width height +============== +*/ +void Cmd_Raw (void) +{ + int xl,yl,w,h,y; + byte *cropped; + char savename[1024]; + char dest[1024]; + + GetToken (qfalse); + + sprintf (savename, "%s%s.lmp", writedir, token); + + if (g_release) + { + sprintf (dest, "%s.lmp", 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 ; y<h ; y++) + { + memcpy (cropped+y*w, byteimage+(y+yl)*byteimagewidth+xl, w); + } + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + + SaveFile (savename, cropped, w*h); + + free (cropped); +} + +/* +============================================================================= + +COLORMAP GRABBING + +============================================================================= +*/ + +/* +=============== +BestColor +=============== +*/ +byte BestColor (int r, int g, int b, int start, int stop) +{ + int i; + int dr, dg, db; + int bestdistortion, distortion; + int bestcolor; + byte *pal; + +// +// let any color go to 0 as a last resort +// + bestdistortion = 256*256*4; + bestcolor = 0; + + pal = colormap_palette + start*3; + for (i=start ; i<= stop ; i++) + { + dr = r - (int)pal[0]; + dg = g - (int)pal[1]; + db = b - (int)pal[2]; + pal += 3; + distortion = dr*dr + dg*dg + db*db; + if (distortion < bestdistortion) + { + if (!distortion) + return i; // perfect match + + bestdistortion = distortion; + bestcolor = i; + } + } + + return bestcolor; +} + + +/* +============== +Cmd_Colormap + +$colormap filename + + the brightes colormap is first in the table (FIXME: reverse this now?) + + 64 rows of 256 : lightmaps + 256 rows of 256 : translucency table +============== +*/ +void Cmd_Colormap (void) +{ + int levels, brights; + int l, c; + float frac, red, green, blue; + float range; + byte *cropped, *lump_p; + char savename[1024]; + char dest[1024]; + + colormap_issued = qtrue; + if (!g_release) + memcpy (colormap_palette, lbmpalette, 768); + + if (!TokenAvailable ()) + { // just setting colormap_issued + return; + } + + GetToken (qfalse); + sprintf (savename, "%spics/%s.pcx", writedir, token); + + if (g_release) + { + sprintf (dest, "pics/%s.pcx", token); + ReleaseFile (dest); + return; + } + + range = 2; + levels = 64; + brights = 1; // ignore 255 (transparent) + + cropped = malloc((levels+256)*256); + lump_p = cropped; + +// shaded levels + for (l=0;l<levels;l++) + { + frac = range - range*(float)l/(levels-1); + for (c=0 ; c<256-brights ; c++) + { + red = lbmpalette[c*3]; + green = lbmpalette[c*3+1]; + blue = lbmpalette[c*3+2]; + + red = (int)(red*frac+0.5); + green = (int)(green*frac+0.5); + blue = (int)(blue*frac+0.5); + +// +// note: 254 instead of 255 because 255 is the transparent color, and we +// don't want anything remapping to that +// don't use color 0, because NT can't remap that (or 255) +// + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + + // fullbrights allways stay the same + for ( ; c<256 ; c++) + *lump_p++ = c; + } + +// 66% transparancy table + for (l=0;l<255;l++) + { + for (c=0 ; c<255 ; c++) + { + red = lbmpalette[c*3]*0.33 + lbmpalette[l*3]*0.66; + green = lbmpalette[c*3+1]*0.33 + lbmpalette[l*3+1]*0.66; + blue = lbmpalette[c*3+2]*0.33 + lbmpalette[l*3+2]*0.66; + + *lump_p++ = BestColor(red,green,blue, 1, 254); + } + *lump_p++ = 255; + } + for (c=0 ; c<256 ; c++) + *lump_p++ = 255; + + // save off the new image + printf ("saving %s\n", savename); + CreatePath (savename); + WritePCXfile (savename, cropped, 256, levels+256, lbmpalette); + + free (cropped); +} + +/* +============================================================================= + +MIPTEX GRABBING + +============================================================================= +*/ + +byte pixdata[256]; + +int d_red, d_green, d_blue; + +byte palmap[32][32][32]; +qboolean palmap_built; + +/* +============= +FindColor +============= +*/ +int FindColor (int r, int g, int b) +{ + int bestcolor; + + if (r > 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<count ; i++) + { + pix = pixdata[i]; + + r += lbmpalette[pix*3]; + g += lbmpalette[pix*3+1]; + b += lbmpalette[pix*3+2]; + vis++; + } + + r /= vis; + g /= vis; + b /= vis; + + // error diffusion + r += d_red; + g += d_green; + b += d_blue; + +// +// find the best color +// + bestcolor = FindColor (r, g, b); + + // error diffusion + pal = colormap_palette + bestcolor*3; + d_red = r - (int)pal[0]; + d_green = g - (int)pal[1]; + d_blue = b - (int)pal[2]; + + return bestcolor; +} + + + +/* +============================================================================= + +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; + + GetToken (qfalse); + + 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", writedir, 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/quake3/q3data/md3lib.c b/tools/quake3/q3data/md3lib.c index 5bc90b10..e959a411 100644 --- a/tools/quake3/q3data/md3lib.c +++ b/tools/quake3/q3data/md3lib.c @@ -1,193 +1,193 @@ -#include <assert.h> -#ifdef _WIN32 -#include <io.h> -#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 ); -} - +#include <assert.h> +#ifdef _WIN32 +#include <io.h> +#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 index 7132906f..bdee0bd9 100644 --- a/tools/quake3/q3data/md3lib.h +++ b/tools/quake3/q3data/md3lib.h @@ -1,7 +1,7 @@ -#include <stdio.h> -#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] ); +#include <stdio.h> +#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 index 05d65df7..1d2d6904 100644 --- a/tools/quake3/q3data/models.c +++ b/tools/quake3/q3data/models.c @@ -1,2134 +1,2134 @@ -#include <assert.h> -#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 ; f<g_data.model.numFrames; f++) - { - int t; - - for ( t = 0; t < g_data.model.numTags; t++ ) - { - g_data.tags[f][t].origin[0] = LittleFloat(g_data.tags[f][t].origin[0]); - g_data.tags[f][t].origin[1] = LittleFloat(g_data.tags[f][t].origin[1]); - g_data.tags[f][t].origin[2] = LittleFloat(g_data.tags[f][t].origin[2]); - - for (j=0 ; j<3 ; j++) - { - g_data.tags[f][t].axis[0][j] = LittleFloat(g_data.tags[f][t].axis[0][j]); - g_data.tags[f][t].axis[1][j] = LittleFloat(g_data.tags[f][t].axis[1][j]); - g_data.tags[f][t].axis[2][j] = LittleFloat(g_data.tags[f][t].axis[2][j]); - } - } - SafeWrite( modelouthandle, g_data.tags[f], g_data.model.numTags * sizeof(md3Tag_t) ); - } - - // - // write out the surfaces - // - fseek( modelouthandle, g_data.model.ofsSurfaces, SEEK_SET ); - for ( i = 0; i < g_data.model.numSurfaces; i++ ) - { - WriteModelSurface( modelouthandle, &g_data.surfData[i] ); - } -} - - -/* -=============== -FinishModel -=============== -*/ -void FinishModel ( int type ) -{ - FILE *modelouthandle; - FILE *defaultSkinHandle; - char name[1024]; - int i; - - if (!g_data.model.numFrames) - return; - - // - // build generalized triangle strips - // - OrderSurfaces(); - - if ( type == TYPE_PLAYER ) - { - sprintf( name, "%s%s", writedir, g_modelname ); - *strrchr( name, '.' ) = 0; - strcat( name, "_default.skin" ); - - defaultSkinHandle = fopen( name, "wt" ); - for ( i = 0; i < g_data.model.numSurfaces; i++ ) - { - fprintf( defaultSkinHandle, "%s,%s\n", g_data.surfData[i].header.name, g_data.surfData[i].shaders[0].name ); - } - fclose( defaultSkinHandle ); - } - - sprintf (name, "%s%s", writedir, g_modelname); - - // - // copy the model and its shaders to release directory tree - // if doing a release build - // - if ( g_release ) { - int i, j; - md3SurfaceData_t *pSurf; - - ReleaseFile( g_modelname ); - - for ( i = 0; i < g_data.model.numSurfaces; i++ ) { - pSurf = &g_data.surfData[i]; - for ( j = 0; j < g_data.model.numSkins; j++ ) { - ReleaseShader( pSurf->shaders[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<numtri ; i++) - for (j=0 ; j<3 ; j++) - AddPointToBounds (ptri[i].verts[j], mins, maxs); - - for (i=0 ; i<3 ; i++) - { - mins[i] = floor(mins[i]); - maxs[i] = ceil(maxs[i]); - } - - width = maxs[0] - mins[0]; - height = maxs[2] - mins[2]; - - if (!g_data.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_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; i<numtri ; i++, ptri++, bTri++) - { - int j; - - for (j=0 ; j<3 ; j++) - { - pbasevert = ptri->verts[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(); -} +#include <assert.h> +#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 ; f<g_data.model.numFrames; f++) + { + int t; + + for ( t = 0; t < g_data.model.numTags; t++ ) + { + g_data.tags[f][t].origin[0] = LittleFloat(g_data.tags[f][t].origin[0]); + g_data.tags[f][t].origin[1] = LittleFloat(g_data.tags[f][t].origin[1]); + g_data.tags[f][t].origin[2] = LittleFloat(g_data.tags[f][t].origin[2]); + + for (j=0 ; j<3 ; j++) + { + g_data.tags[f][t].axis[0][j] = LittleFloat(g_data.tags[f][t].axis[0][j]); + g_data.tags[f][t].axis[1][j] = LittleFloat(g_data.tags[f][t].axis[1][j]); + g_data.tags[f][t].axis[2][j] = LittleFloat(g_data.tags[f][t].axis[2][j]); + } + } + SafeWrite( modelouthandle, g_data.tags[f], g_data.model.numTags * sizeof(md3Tag_t) ); + } + + // + // write out the surfaces + // + fseek( modelouthandle, g_data.model.ofsSurfaces, SEEK_SET ); + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + WriteModelSurface( modelouthandle, &g_data.surfData[i] ); + } +} + + +/* +=============== +FinishModel +=============== +*/ +void FinishModel ( int type ) +{ + FILE *modelouthandle; + FILE *defaultSkinHandle; + char name[1024]; + int i; + + if (!g_data.model.numFrames) + return; + + // + // build generalized triangle strips + // + OrderSurfaces(); + + if ( type == TYPE_PLAYER ) + { + sprintf( name, "%s%s", writedir, g_modelname ); + *strrchr( name, '.' ) = 0; + strcat( name, "_default.skin" ); + + defaultSkinHandle = fopen( name, "wt" ); + for ( i = 0; i < g_data.model.numSurfaces; i++ ) + { + fprintf( defaultSkinHandle, "%s,%s\n", g_data.surfData[i].header.name, g_data.surfData[i].shaders[0].name ); + } + fclose( defaultSkinHandle ); + } + + sprintf (name, "%s%s", writedir, g_modelname); + + // + // copy the model and its shaders to release directory tree + // if doing a release build + // + if ( g_release ) { + int i, j; + md3SurfaceData_t *pSurf; + + ReleaseFile( g_modelname ); + + for ( i = 0; i < g_data.model.numSurfaces; i++ ) { + pSurf = &g_data.surfData[i]; + for ( j = 0; j < g_data.model.numSkins; j++ ) { + ReleaseShader( pSurf->shaders[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<numtri ; i++) + for (j=0 ; j<3 ; j++) + AddPointToBounds (ptri[i].verts[j], mins, maxs); + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + if (!g_data.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_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; i<numtri ; i++, ptri++, bTri++) + { + int j; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri->verts[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 index 2444f95e..c6083cf5 100644 --- a/tools/quake3/q3data/oldstuff.c +++ b/tools/quake3/q3data/oldstuff.c @@ -1,130 +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 +#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 index 6afc3491..0c3b6026 100644 --- a/tools/quake3/q3data/p3dlib.c +++ b/tools/quake3/q3data/p3dlib.c @@ -1,324 +1,324 @@ -#include "p3dlib.h" - -#ifdef _WIN32 -#include <io.h> -#endif -#include <stdlib.h> -#include <stdio.h> -#include <string.h> - -#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 - - +#include "p3dlib.h" + +#ifdef _WIN32 +#include <io.h> +#endif +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#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 index a6c0320d..24e446d1 100644 --- a/tools/quake3/q3data/p3dlib.h +++ b/tools/quake3/q3data/p3dlib.h @@ -1,8 +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 ); + +#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 index 794fc026..f89a8cc0 100644 --- a/tools/quake3/q3data/polyset.c +++ b/tools/quake3/q3data/polyset.c @@ -1,252 +1,252 @@ -#include <assert.h> -#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] ); - } - } -} - +#include <assert.h> +#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 index 05ff9220..202f21dd 100644 --- a/tools/quake3/q3data/q3data.c +++ b/tools/quake3/q3data/q3data.c @@ -1,643 +1,643 @@ -#ifdef _WIN32 -#include <io.h> -#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 <sys/types.h> -#ifndef WIN32 -#include <sys/dir.h> -#else -#include <sys/dirent.h> -#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 ; i<count ; i++) - { - ent = namelist[i]; - name = ent->d_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<numrtex ; i++) - if (!Q_stricmp(name, rtex[i])) - return; - - if (numrtex == MAX_RTEX) - Error ("numrtex == MAX_RTEX"); - - strcpy (rtex[i], name); - numrtex++; - - sprintf (path, "textures/%s.wal", name); - ReleaseFile (path); -} - -/* -=============== -Cmd_Maps - -Only relevent for release and pak files. -Releases the .bsp files for the maps, and scans all of the files to -build a list of all textures used, which are then released. -=============== -*/ -void Cmd_Maps (void) -{ - char map[1024]; - - while (TokenAvailable ()) - { - GetToken (qfalse); - sprintf (map, "maps/%s.bsp", token); - ReleaseFile (map); - - if (!g_release) - continue; - - // get all the texture references - sprintf (map, "%smaps/%s.bsp", gamedir, token); - LoadBSPFile( map ); - } -} - - -//============================================================== - -/* -=============== -ParseScript -=============== -*/ -void ParseScript (void) -{ - while (1) - { - do - { // look for a line starting with a $ command - GetToken (qtrue); - if (endofscript) - return; - if (token[0] == '$') - break; - while (TokenAvailable()) - GetToken (qfalse); - } while (1); - - // - // model commands - // - if (!strcmp (token, "$modelname")) - Cmd_Modelname (); - else if (!strcmp (token, "$base")) - Cmd_Base (); - else if ( !strcmp( token, "$exit" ) ) - break; - else if ( !strcmp( token, "$3dsconvert" ) ) - Cmd_3DSConvert(); - else if (!strcmp (token, "$spritebase")) - Cmd_SpriteBase (); - else if (!strcmp (token, "$cd")) - Cmd_Cd (); - else if (!strcmp (token, "$origin")) - Cmd_Origin (); - else if (!strcmp (token, "$scale")) - Cmd_ScaleUp (); - else if (!strcmp (token, "$frame")) - Cmd_Frame (); - else if (!strcmp (token, "$skin" )) - Cmd_Skin(); - else if (!strcmp (token, "$spriteshader")) - Cmd_SpriteShader(); - else if (!strcmp( token, "$aseconvert" )) - Cmd_ASEConvert( qfalse ); - else if (!strcmp( token, "$aseanimconvert" ) ) - Cmd_ASEConvert( qtrue ); - - // - // image commands - // - else if (!strcmp (token, "$grab")) - Cmd_Grab (); - else if (!strcmp (token, "$raw")) - Cmd_Raw (); - else if (!strcmp (token, "$colormap")) - Cmd_Colormap (); - else if (!strcmp (token, "$environment")) - Cmd_Environment (); - - // - // video - // - else if (!strcmp (token, "$video")) - Cmd_Video (); - // - // misc - // - else if (!strcmp (token, "$file")) - Cmd_File (); - else if (!strcmp (token, "$dir")) - Cmd_Dir (); - else if (!strcmp (token, "$maps")) - Cmd_Maps (); - else - Error ("bad command %s\n", token); - } -} - -//======================================================= - -#include "version.h" - -/* -============== -main -============== -*/ -int main (int argc, char **argv) -{ - static int i; // VC4.2 compiler bug if auto... - char path[1024]; - - // using GtkRadiant's versioning next to Id's versioning - printf ("Q3Data - (c) 1999 Id Software Inc.\n"); - printf ("GtkRadiant - v" RADIANT_VERSION " " __DATE__ "\n"); - - ExpandWildcards (&argc, &argv); - - for (i=1 ; i<argc ; i++) - { - if (!strcmp(argv[i], "-archive")) - { - archive = qtrue; - strcpy (archivedir, argv[i+1]); - printf ("Archiving source to: %s\n", archivedir); - i++; - } - else if (!strcmp(argv[i], "-release")) - { - g_release = qtrue; - strcpy (g_releasedir, argv[i+1]); - printf ("Copy output to: %s\n", g_releasedir); - i++; - } - else if ( !strcmp( argv[i], "-nostrips" ) ) - { - g_stripify = qfalse; - printf( "Not optimizing for strips\n" ); - } - else if ( !strcmp( argv[i], "-writedir" ) ) - { - strcpy( writedir, argv[i+1] ); - printf( "Write output to: %s\n", writedir ); - i++; - } - else if ( !strcmp( argv[i], "-verbose" ) ) - { - g_verbose = qtrue; - } - else if ( !strcmp( argv[i], "-dump" ) ) - { - printf( "Dumping contents of: '%s'\n", argv[i+1] ); - if ( strstr( argv[i+1], ".md3" ) ) - { - MD3_Dump( argv[i+1] ); - } - else - { - Error( "Do not know how to dump the contents of '%s'\n", argv[i+1] ); - } - i++; - } - else if ( !strcmp( argv[i], "-3dsconvert" ) ) - { - // NOTE TTimo this is broken, tried on a sample .3ds - // what happens .. it calls the Convert3DStoMD3, - // which calls the scriptlib function in non initialized state .. and crashes - printf( "Converting %s.3DS to %s.MD3\n", argv[i+1], argv[i+1] ); - SetQdirFromPath( argv[i+1] ); - vfsInitDirectory( gamedir ); - Convert3DStoMD3( argv[i+1] ); - i++; - } - else if (!strcmp(argv[i], "-only")) - { - strcpy (g_only, argv[i+1]); - printf ("Only grabbing %s\n", g_only); - i++; - } - else if (!strcmp(argv[i], "-gamedir")) - { - strcpy(gamedir, argv[i+1]); - i++; - } - else if (argv[i][0] == '-') - Error ("Unknown option \"%s\"", argv[i]); - else - break; - } - - if (i == argc) - Error ("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]"); - - for ( ; i<argc ; i++) - { - printf ("--------------- %s ---------------\n", argv[i]); - // load the script - strcpy (path, argv[i]); - DefaultExtension (path, ".qdt"); - if(!gamedir[0]) - SetQdirFromPath (path); - // NOTE TTimo - // q3data went through a partial conversion to use the vfs - // it was never actually tested before 1.1.1 - // the code is still mostly using direct file access calls - vfsInitDirectory( gamedir ); - LoadScriptFile (ExpandArg(path), -1); - - // - // parse it - // - ParseScript (); - - // write out the last model - FinishModel ( TYPE_UNKNOWN ); - } - - return 0; -} - +#ifdef _WIN32 +#include <io.h> +#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 <sys/types.h> +#ifndef WIN32 +#include <sys/dir.h> +#else +#include <sys/dirent.h> +#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 ; i<count ; i++) + { + ent = namelist[i]; + name = ent->d_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<numrtex ; i++) + if (!Q_stricmp(name, rtex[i])) + return; + + if (numrtex == MAX_RTEX) + Error ("numrtex == MAX_RTEX"); + + strcpy (rtex[i], name); + numrtex++; + + sprintf (path, "textures/%s.wal", name); + ReleaseFile (path); +} + +/* +=============== +Cmd_Maps + +Only relevent for release and pak files. +Releases the .bsp files for the maps, and scans all of the files to +build a list of all textures used, which are then released. +=============== +*/ +void Cmd_Maps (void) +{ + char map[1024]; + + while (TokenAvailable ()) + { + GetToken (qfalse); + sprintf (map, "maps/%s.bsp", token); + ReleaseFile (map); + + if (!g_release) + continue; + + // get all the texture references + sprintf (map, "%smaps/%s.bsp", gamedir, token); + LoadBSPFile( map ); + } +} + + +//============================================================== + +/* +=============== +ParseScript +=============== +*/ +void ParseScript (void) +{ + while (1) + { + do + { // look for a line starting with a $ command + GetToken (qtrue); + if (endofscript) + return; + if (token[0] == '$') + break; + while (TokenAvailable()) + GetToken (qfalse); + } while (1); + + // + // model commands + // + if (!strcmp (token, "$modelname")) + Cmd_Modelname (); + else if (!strcmp (token, "$base")) + Cmd_Base (); + else if ( !strcmp( token, "$exit" ) ) + break; + else if ( !strcmp( token, "$3dsconvert" ) ) + Cmd_3DSConvert(); + else if (!strcmp (token, "$spritebase")) + Cmd_SpriteBase (); + else if (!strcmp (token, "$cd")) + Cmd_Cd (); + else if (!strcmp (token, "$origin")) + Cmd_Origin (); + else if (!strcmp (token, "$scale")) + Cmd_ScaleUp (); + else if (!strcmp (token, "$frame")) + Cmd_Frame (); + else if (!strcmp (token, "$skin" )) + Cmd_Skin(); + else if (!strcmp (token, "$spriteshader")) + Cmd_SpriteShader(); + else if (!strcmp( token, "$aseconvert" )) + Cmd_ASEConvert( qfalse ); + else if (!strcmp( token, "$aseanimconvert" ) ) + Cmd_ASEConvert( qtrue ); + + // + // image commands + // + else if (!strcmp (token, "$grab")) + Cmd_Grab (); + else if (!strcmp (token, "$raw")) + Cmd_Raw (); + else if (!strcmp (token, "$colormap")) + Cmd_Colormap (); + else if (!strcmp (token, "$environment")) + Cmd_Environment (); + + // + // video + // + else if (!strcmp (token, "$video")) + Cmd_Video (); + // + // misc + // + else if (!strcmp (token, "$file")) + Cmd_File (); + else if (!strcmp (token, "$dir")) + Cmd_Dir (); + else if (!strcmp (token, "$maps")) + Cmd_Maps (); + else + Error ("bad command %s\n", token); + } +} + +//======================================================= + +#include "version.h" + +/* +============== +main +============== +*/ +int main (int argc, char **argv) +{ + static int i; // VC4.2 compiler bug if auto... + char path[1024]; + + // using GtkRadiant's versioning next to Id's versioning + printf ("Q3Data - (c) 1999 Id Software Inc.\n"); + printf ("GtkRadiant - v" RADIANT_VERSION " " __DATE__ "\n"); + + ExpandWildcards (&argc, &argv); + + for (i=1 ; i<argc ; i++) + { + if (!strcmp(argv[i], "-archive")) + { + archive = qtrue; + strcpy (archivedir, argv[i+1]); + printf ("Archiving source to: %s\n", archivedir); + i++; + } + else if (!strcmp(argv[i], "-release")) + { + g_release = qtrue; + strcpy (g_releasedir, argv[i+1]); + printf ("Copy output to: %s\n", g_releasedir); + i++; + } + else if ( !strcmp( argv[i], "-nostrips" ) ) + { + g_stripify = qfalse; + printf( "Not optimizing for strips\n" ); + } + else if ( !strcmp( argv[i], "-writedir" ) ) + { + strcpy( writedir, argv[i+1] ); + printf( "Write output to: %s\n", writedir ); + i++; + } + else if ( !strcmp( argv[i], "-verbose" ) ) + { + g_verbose = qtrue; + } + else if ( !strcmp( argv[i], "-dump" ) ) + { + printf( "Dumping contents of: '%s'\n", argv[i+1] ); + if ( strstr( argv[i+1], ".md3" ) ) + { + MD3_Dump( argv[i+1] ); + } + else + { + Error( "Do not know how to dump the contents of '%s'\n", argv[i+1] ); + } + i++; + } + else if ( !strcmp( argv[i], "-3dsconvert" ) ) + { + // NOTE TTimo this is broken, tried on a sample .3ds + // what happens .. it calls the Convert3DStoMD3, + // which calls the scriptlib function in non initialized state .. and crashes + printf( "Converting %s.3DS to %s.MD3\n", argv[i+1], argv[i+1] ); + SetQdirFromPath( argv[i+1] ); + vfsInitDirectory( gamedir ); + Convert3DStoMD3( argv[i+1] ); + i++; + } + else if (!strcmp(argv[i], "-only")) + { + strcpy (g_only, argv[i+1]); + printf ("Only grabbing %s\n", g_only); + i++; + } + else if (!strcmp(argv[i], "-gamedir")) + { + strcpy(gamedir, argv[i+1]); + i++; + } + else if (argv[i][0] == '-') + Error ("Unknown option \"%s\"", argv[i]); + else + break; + } + + if (i == argc) + Error ("usage: q3data [-archive <directory>] [-dump <file.md3>] [-release <directory>] [-only <model>] [-3dsconvert <file.3ds>] [-verbose] [file.qdt]"); + + for ( ; i<argc ; i++) + { + printf ("--------------- %s ---------------\n", argv[i]); + // load the script + strcpy (path, argv[i]); + DefaultExtension (path, ".qdt"); + if(!gamedir[0]) + SetQdirFromPath (path); + // NOTE TTimo + // q3data went through a partial conversion to use the vfs + // it was never actually tested before 1.1.1 + // the code is still mostly using direct file access calls + vfsInitDirectory( gamedir ); + LoadScriptFile (ExpandArg(path), -1); + + // + // parse it + // + ParseScript (); + + // write out the last model + FinishModel ( TYPE_UNKNOWN ); + } + + return 0; +} + diff --git a/tools/quake3/q3data/q3data.h b/tools/quake3/q3data/q3data.h index a8939513..458d4ed6 100644 --- a/tools/quake3/q3data/q3data.h +++ b/tools/quake3/q3data/q3data.h @@ -1,78 +1,78 @@ -// q3data.h - - -#include <stdlib.h> -#include <stdio.h> -#include <math.h> -#include <string.h> -#include <sys/stat.h> - -#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 +// q3data.h + + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <sys/stat.h> + +#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/stripper.c b/tools/quake3/q3data/stripper.c index 8229aba3..c42d4420 100644 --- a/tools/quake3/q3data/stripper.c +++ b/tools/quake3/q3data/stripper.c @@ -1,282 +1,282 @@ -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -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 ); -} +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +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 index 35e097bf..9054d5e9 100644 --- a/tools/quake3/q3data/video.c +++ b/tools/quake3/q3data/video.c @@ -1,1132 +1,1132 @@ -#include <assert.h> -#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<j ; i++) - { - val = ((unsigned short *)( s_soundtrack + s_wavinfo.dataofs))[i]; - s_samplecounts[val]++; - } - val = 0; - for (i=0 ; i<0x10000 ; i++) - if (s_samplecounts[i]) - val++; - - printf ("%i unique sample values\n", val); -} - -/* -================== -WriteSound -================== -*/ -void WriteSound (FILE *output, int frame) -{ - int start, end; - int count; - int empty = 0; - int i; - int sample; - int width; - - width = s_wavinfo.width * s_wavinfo.channels; - - start = frame*s_wavinfo.rate/14; - end = (frame+1)*s_wavinfo.rate/14; - count = end - start; - - for (i=0 ; i<count ; i++) - { - sample = start+i; - if (sample > 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 <directory> <framedigits> -=============== -*/ -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; - } -} +#include <assert.h> +#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<j ; i++) + { + val = ((unsigned short *)( s_soundtrack + s_wavinfo.dataofs))[i]; + s_samplecounts[val]++; + } + val = 0; + for (i=0 ; i<0x10000 ; i++) + if (s_samplecounts[i]) + val++; + + printf ("%i unique sample values\n", val); +} + +/* +================== +WriteSound +================== +*/ +void WriteSound (FILE *output, int frame) +{ + int start, end; + int count; + int empty = 0; + int i; + int sample; + int width; + + width = s_wavinfo.width * s_wavinfo.channels; + + start = frame*s_wavinfo.rate/14; + end = (frame+1)*s_wavinfo.rate/14; + count = end - start; + + for (i=0 ; i<count ; i++) + { + sample = start+i; + if (sample > 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 <directory> <framedigits> +=============== +*/ +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/brush.c b/tools/quake3/q3map2/brush.c index eebc097f..28ade081 100644 --- a/tools/quake3/q3map2/brush.c +++ b/tools/quake3/q3map2/brush.c @@ -1,982 +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 ; i<brush->numsides ; 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 ( ; i<brush->numsides ; 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 ; i<list->numsides ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<brush->numsides ; i++) - { - w = brush->sides[i].winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) - { - w = brush->sides[i].winding; - if (!w) - continue; - for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides && 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 ; i<brush->numsides ; 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]; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<brush->numsides ; 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 ( ; i<brush->numsides ; 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 ; i<list->numsides ; 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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 ; i<brush->numsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; j<w->numpoints ; 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 ; i<brush->numsides && 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 ; i<brush->numsides ; 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 index ae0110d6..9bc2ab62 100644 --- a/tools/quake3/q3map2/brush_primit.c +++ b/tools/quake3/q3map2/brush_primit.c @@ -1,80 +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 ); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index c73242da..ed3d2430 100644 --- a/tools/quake3/q3map2/bsp.c +++ b/tools/quake3/q3map2/bsp.c @@ -1,853 +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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index db34dd61..ae2fec30 100644 --- a/tools/quake3/q3map2/bspfile_abstract.c +++ b/tools/quake3/q3map2/bspfile_abstract.c @@ -1,834 +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 ); - } -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index dddf63ca..71b982da 100644 --- a/tools/quake3/q3map2/bspfile_ibsp.c +++ b/tools/quake3/q3map2/bspfile_ibsp.c @@ -1,584 +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 ); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 2e09510c..1f4f1f77 100644 --- a/tools/quake3/q3map2/bspfile_rbsp.c +++ b/tools/quake3/q3map2/bspfile_rbsp.c @@ -1,339 +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 ); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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/convert_ase.c b/tools/quake3/q3map2/convert_ase.c index 1d937c76..f0ac6df5 100644 --- a/tools/quake3/q3map2/convert_ase.c +++ b/tools/quake3/q3map2/convert_ase.c @@ -1,374 +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; -} - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index ff69c8a5..ca0ba7fb 100644 --- a/tools/quake3/q3map2/convert_map.c +++ b/tools/quake3/q3map2/convert_map.c @@ -1,443 +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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index d7b01d64..5260437d 100644 --- a/tools/quake3/q3map2/decals.c +++ b/tools/quake3/q3map2/decals.c @@ -1,908 +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 ); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index b92facc4..484a7489 100644 --- a/tools/quake3/q3map2/facebsp.c +++ b/tools/quake3/q3map2/facebsp.c @@ -1,453 +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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 70348099..0cfdc924 100644 --- a/tools/quake3/q3map2/fog.c +++ b/tools/quake3/q3map2/fog.c @@ -1,804 +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 ); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 6b1c7bfa..8d15c732 100644 --- a/tools/quake3/q3map2/game_ef.h +++ b/tools/quake3/q3map2/game_ef.h @@ -1,186 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index f0f8b276..d7b39762 100644 --- a/tools/quake3/q3map2/game_ja.h +++ b/tools/quake3/q3map2/game_ja.h @@ -1,180 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 8fbf7202..086eaced 100644 --- a/tools/quake3/q3map2/game_jk2.h +++ b/tools/quake3/q3map2/game_jk2.h @@ -1,174 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 27910473..9b55787d 100644 --- a/tools/quake3/q3map2/game_quake3.h +++ b/tools/quake3/q3map2/game_quake3.h @@ -1,184 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index cd3c7a38..5d12d07d 100644 --- a/tools/quake3/q3map2/game_sof2.h +++ b/tools/quake3/q3map2/game_sof2.h @@ -1,249 +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 +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 319b1f78..5eec9063 100644 --- a/tools/quake3/q3map2/game_t.h +++ b/tools/quake3/q3map2/game_t.h @@ -1,34 +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; - + +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index bfa2f031..a639288f 100644 --- a/tools/quake3/q3map2/game_tenebrae.h +++ b/tools/quake3/q3map2/game_tenebrae.h @@ -1,184 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index b1184a3e..0e882868 100644 --- a/tools/quake3/q3map2/game_wolf.h +++ b/tools/quake3/q3map2/game_wolf.h @@ -1,230 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 080e7fc9..fdc5b7e8 100644 --- a/tools/quake3/q3map2/game_wolfet.h +++ b/tools/quake3/q3map2/game_wolfet.h @@ -1,169 +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 - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 26e0e24f..fec9f6f5 100644 --- a/tools/quake3/q3map2/image.c +++ b/tools/quake3/q3map2/image.c @@ -1,467 +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; -} - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e8108c6f..1d72604b 100644 --- a/tools/quake3/q3map2/leakfile.c +++ b/tools/quake3/q3map2/leakfile.c @@ -1,126 +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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 9ee61bea..670c9a0e 100644 --- a/tools/quake3/q3map2/light.c +++ b/tools/quake3/q3map2/light.c @@ -1,2182 +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; -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e4d23da3..4181ce53 100644 --- a/tools/quake3/q3map2/light_bounce.c +++ b/tools/quake3/q3map2/light_bounce.c @@ -1,954 +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 ); -} - - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 14a18d95..df7cdd82 100644 --- a/tools/quake3/q3map2/light_shadows.c +++ b/tools/quake3/q3map2/light_shadows.c @@ -1,124 +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; - } - } - } +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 91fc25ec..287b22dd 100644 --- a/tools/quake3/q3map2/light_trace.c +++ b/tools/quake3/q3map2/light_trace.c @@ -1,1754 +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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 33be2071..6a292156 100644 --- a/tools/quake3/q3map2/light_ydnar.c +++ b/tools/quake3/q3map2/light_ydnar.c @@ -1,3129 +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 ); -} - - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index c79dfb40..62977ddf 100644 --- a/tools/quake3/q3map2/lightmaps.c +++ b/tools/quake3/q3map2/lightmaps.c @@ -1,496 +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<w ; j++) { - if (allocated[i+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 ; i<w ; i++) { - allocated[*x + i] = best + h; - } - - return qtrue; -} - - -/* -=================== -AllocateLightmapForPatch -=================== -*/ -//#define LIGHTMAP_PATCHSHIFT - -void AllocateLightmapForPatch( mapDrawSurface_t *ds ) -{ - int i, j, k; - drawVert_t *verts; - int w, h; - int x, y; - float s, t; - mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh; - int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize; - - verts = ds->verts; - - 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 ); -} - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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<w ; j++) { + if (allocated[i+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 ; i<w ; i++) { + allocated[*x + i] = best + h; + } + + return qtrue; +} + + +/* +=================== +AllocateLightmapForPatch +=================== +*/ +//#define LIGHTMAP_PATCHSHIFT + +void AllocateLightmapForPatch( mapDrawSurface_t *ds ) +{ + int i, j, k; + drawVert_t *verts; + int w, h; + int x, y; + float s, t; + mesh_t mesh, *subdividedMesh, *tempMesh, *newmesh; + int widthtable[LIGHTMAP_WIDTH], heighttable[LIGHTMAP_HEIGHT], ssize; + + verts = ds->verts; + + 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 index 22b6e376..df169351 100644 --- a/tools/quake3/q3map2/lightmaps_ydnar.c +++ b/tools/quake3/q3map2/lightmaps_ydnar.c @@ -1,2997 +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] <mapname>\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] <mapname>\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(); -} - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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] <mapname>\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] <mapname>\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/main.c b/tools/quake3/q3map2/main.c index 40fd5c8c..4da3bcf8 100644 --- a/tools/quake3/q3map2/main.c +++ b/tools/quake3/q3map2/main.c @@ -1,456 +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 <value> [-v] <mapname>\n" ); - return 0; - } - - /* get scale */ - scale = atof( argv[ argc - 2 ] ); - if( scale == 0.0f ) - { - Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\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 <value> [-v] <mapname>\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; -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 <value> [-v] <mapname>\n" ); + return 0; + } + + /* get scale */ + scale = atof( argv[ argc - 2 ] ); + if( scale == 0.0f ) + { + Sys_Printf( "Usage: q3map -scale <value> [-v] <mapname>\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 <value> [-v] <mapname>\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 index dbc71f14..633d327a 100644 --- a/tools/quake3/q3map2/map.c +++ b/tools/quake3/q3map2/map.c @@ -1,1649 +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 ); - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index f1cccf04..6348d577 100644 --- a/tools/quake3/q3map2/mesh.c +++ b/tools/quake3/q3map2/mesh.c @@ -1,825 +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); -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 15192e2a..f303df75 100644 --- a/tools/quake3/q3map2/model.c +++ b/tools/quake3/q3map2/model.c @@ -1,706 +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; - } - } -} +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index a9542004..a1134db3 100644 --- a/tools/quake3/q3map2/patch.c +++ b/tools/quake3/q3map2/patch.c @@ -1,524 +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 ); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index e90b382d..80e3c6d3 100644 --- a/tools/quake3/q3map2/path_init.c +++ b/tools/quake3/q3map2/path_init.c @@ -1,456 +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" ); -} - - - - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 index 0b3cdfd3..59ed6daf 100644 --- a/tools/quake3/q3map2/portals.c +++ b/tools/quake3/q3map2/portals.c @@ -1,970 +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 ; i<w->numpoints ; 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 ; i<p->winding->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 ); -} - - -//============================================================== - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<p->winding->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 index ab7c5304..43fcbb03 100644 --- a/tools/quake3/q3map2/prtfile.c +++ b/tools/quake3/q3map2/prtfile.c @@ -1,291 +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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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); -} - +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General 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 ; i<w->numpoints ; 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 ; i<w->numpoints ; 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->