Repository: codereader/DarkRadiant Branch: master Commit: 0be7b2d1f8cc Files: 2658 Total size: 26.7 MB Directory structure: gitextract_d_ogn0ar/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .gitlab-ci.yml ├── AUTHORS ├── CMakeLists.txt ├── DarkRadiant.sln ├── Doxyfile ├── GPL ├── LICENSE ├── NEWS ├── PKGBUILD ├── README.md ├── config.h.in ├── darkradiant.spec ├── debian/ │ ├── README │ ├── changelog │ ├── compat │ ├── control │ ├── copyright │ ├── darkradiant-i18n.install │ ├── darkradiant-plugin-git.install │ ├── darkradiant-plugins-darkmod.install │ ├── darkradiant.install │ ├── darkradiant.manpages │ ├── dirs │ ├── docs │ ├── rules │ └── source/ │ └── format ├── doc/ │ ├── CMakeLists.txt │ ├── manual.adoc │ ├── manual.css │ └── manual.html ├── include/ │ ├── Bounded.h │ ├── GLProgramAttributes.h │ ├── Rotatable.h │ ├── Scalable.h │ ├── StringSerialisable.h │ ├── Texture.h │ ├── Translatable.h │ ├── VolumeIntersectionValue.h │ ├── editable.h │ ├── i18n.h │ ├── iaasfile.h │ ├── iarchive.h │ ├── iarray.h │ ├── iautosaver.h │ ├── ibrush.h │ ├── icameraview.h │ ├── iclipboard.h │ ├── iclipper.h │ ├── icolourscheme.h │ ├── icommandsystem.h │ ├── icomparablenode.h │ ├── icounter.h │ ├── icurve.h │ ├── idatastream.h │ ├── ideclmanager.h │ ├── idecltypes.h │ ├── ieclass.h │ ├── ieclasscolours.h │ ├── ieditstopwatch.h │ ├── ientity.h │ ├── ifavourites.h │ ├── ifilesystem.h │ ├── ifiletypes.h │ ├── ifilter.h │ ├── ifonts.h │ ├── ifx.h │ ├── igame.h │ ├── igameresource.h │ ├── igeometryrenderer.h │ ├── igeometrystore.h │ ├── igl.h │ ├── iglprogram.h │ ├── igrid.h │ ├── igroupnode.h │ ├── igui.h │ ├── iimage.h │ ├── iinteractiveview.h │ ├── ikeyvaluestore.h │ ├── ilayer.h │ ├── ilightnode.h │ ├── ilogwriter.h │ ├── imanipulator.h │ ├── imap.h │ ├── imapexporter.h │ ├── imapfilechangetracker.h │ ├── imapformat.h │ ├── imapinfofile.h │ ├── imapmerge.h │ ├── imapresource.h │ ├── imd5anim.h │ ├── imd5model.h │ ├── imessagebus.h │ ├── imodel.h │ ├── imodelcache.h │ ├── imodelsurface.h │ ├── imodule.h │ ├── imousetool.h │ ├── imousetoolevent.h │ ├── imousetoolmanager.h │ ├── imru.h │ ├── inameobserver.h │ ├── inamespace.h │ ├── inode.h │ ├── iobjectrenderer.h │ ├── iorthoview.h │ ├── iparticlenode.h │ ├── iparticles.h │ ├── iparticlestage.h │ ├── ipatch.h │ ├── ipath.h │ ├── ipreferencesystem.h │ ├── iradiant.h │ ├── iregion.h │ ├── iregistry.h │ ├── irender.h │ ├── irenderable.h │ ├── irenderableobject.h │ ├── irendersystemfactory.h │ ├── irenderview.h │ ├── iscatter.h │ ├── iscenegraph.h │ ├── iscenegraphfactory.h │ ├── iscript.h │ ├── iscriptinterface.h │ ├── iselectable.h │ ├── iselection.h │ ├── iselectiongroup.h │ ├── iselectionset.h │ ├── iselectiontest.h │ ├── ishaderclipboard.h │ ├── ishaderexpression.h │ ├── ishaderlayer.h │ ├── ishaders.h │ ├── isound.h │ ├── ispacepartition.h │ ├── ispeakernode.h │ ├── isurfacerenderer.h │ ├── itexdef.h │ ├── itextstream.h │ ├── itexturetoolcolours.h │ ├── itexturetoolmodel.h │ ├── itraceable.h │ ├── itransformable.h │ ├── itransformnode.h │ ├── iundo.h │ ├── iversioncontrol.h │ ├── ivolumetest.h │ ├── iwindingrenderer.h │ ├── modelskin.h │ ├── precompiled_interfaces.h │ ├── precompiled_main.h │ ├── precompiled_math.h │ ├── precompiled_render_interfaces.h │ ├── precompiled_ui_interfaces.h │ ├── ui/ │ │ ├── ianimationchooser.h │ │ ├── ideclpreview.h │ │ ├── idialogmanager.h │ │ ├── ientityinspector.h │ │ ├── ieventmanager.h │ │ ├── ifilechooser.h │ │ ├── imainframe.h │ │ ├── imenu.h │ │ ├── imenumanager.h │ │ ├── iorthocontextmenu.h │ │ ├── iresourcechooser.h │ │ ├── istatusbarmanager.h │ │ ├── itoolbarmanager.h │ │ ├── iusercontrol.h │ │ ├── iuserinterface.h │ │ ├── iwindowstate.h │ │ └── iwxgl.h │ └── version.h ├── install/ │ ├── bitmaps/ │ │ ├── .gitignore │ │ └── missing_model.tga │ ├── colours.xml │ ├── commandsystem.xml │ ├── darkradiant.desktop.in │ ├── debug.xml │ ├── games/ │ │ ├── darkmod.game │ │ ├── doom3-demo.game │ │ ├── doom3.game │ │ ├── prey.game │ │ ├── quake3.game │ │ ├── quake4.game │ │ └── xreal.game │ ├── gl/ │ │ ├── blend_light_fp.glsl │ │ ├── blend_light_vp.glsl │ │ ├── cubemap_fp.glsl │ │ ├── cubemap_vp.glsl │ │ ├── interaction_fp.glsl │ │ ├── interaction_vp.glsl │ │ ├── regular_stage_fp.glsl │ │ ├── regular_stage_vp.glsl │ │ ├── shadowmap_fp.glsl │ │ ├── shadowmap_vp.glsl │ │ ├── zfill_alpha_fp.glsl │ │ └── zfill_alpha_vp.glsl │ ├── i18n/ │ │ ├── LINGUAS │ │ ├── Makefile.in.in │ │ ├── Makevars │ │ ├── POTFILES.in │ │ ├── darkradiant.pot │ │ └── de/ │ │ └── LC_MESSAGES/ │ │ ├── darkradiant.mo │ │ └── darkradiant.po │ ├── input.xml │ ├── menu.xml │ ├── net.darkradiant.DarkRadiant.metainfo.xml │ ├── resources/ │ │ └── preview/ │ │ ├── cube.ase │ │ ├── room_cuboid.ase │ │ ├── sphere.ase │ │ └── tiles.ase │ ├── scripts/ │ │ ├── brushtest.py │ │ ├── commands/ │ │ │ ├── ase_export.py │ │ │ ├── ase_export_blend.py │ │ │ ├── check_for_invalid_visportals.py │ │ │ ├── count_loot.py │ │ │ ├── example.py │ │ │ ├── export_obj.py │ │ │ ├── find_duplicate_entities.py │ │ │ ├── patchsplitter.py │ │ │ ├── select_all_models_of_type.py │ │ │ ├── shift_textures_randomly.py │ │ │ ├── shift_textures_upwards_randomly.py │ │ │ └── test_targets.py │ │ ├── dialogtest.py │ │ ├── init.py │ │ ├── materialtest.py │ │ ├── patchtest.py │ │ └── test.py │ ├── ui/ │ │ ├── aboutdialog.fbp │ │ ├── aboutdialog.xrc │ │ ├── addpropertydialog.fbp │ │ ├── addpropertydialog.xrc │ │ ├── arraydialog.fbp │ │ ├── arraydialog.xrc │ │ ├── camwnd.fbp │ │ ├── camwnd.xrc │ │ ├── conversationcmdeditor.fbp │ │ ├── conversationcmdeditor.xrc │ │ ├── conversationdialog.fbp │ │ ├── conversationdialog.xrc │ │ ├── conversationeditor.fbp │ │ ├── conversationeditor.xrc │ │ ├── convertmodeldialog.fbp │ │ ├── convertmodeldialog.xrc │ │ ├── difficultyeditor.fbp │ │ ├── difficultyeditor.xrc │ │ ├── exportasmodeldialog.fbp │ │ ├── exportasmodeldialog.xrc │ │ ├── filterdialog.fbp │ │ ├── filterdialog.xrc │ │ ├── filtereditor.fbp │ │ ├── filtereditor.xrc │ │ ├── findandreplacedialog.fbp │ │ ├── findandreplacedialog.xrc │ │ ├── gameconnection.fbp │ │ ├── gameconnection.xrc │ │ ├── lightinspector.fbp │ │ ├── lightinspector.xrc │ │ ├── materialeditor.fbp │ │ ├── materialeditor.xrc │ │ ├── mergecontroldialog.fbp │ │ ├── mergecontroldialog.xrc │ │ ├── missioninfoeditdialog.fbp │ │ ├── missioninfoeditdialog.xrc │ │ ├── missioninforeadmedialog.fbp │ │ ├── missioninforeadmedialog.xrc │ │ ├── modelselector.fbp │ │ ├── modelselector.xrc │ │ ├── objectivecomponentsdialog.fbp │ │ ├── objectivecomponentsdialog.xrc │ │ ├── objectiveconditionsdialog.fbp │ │ ├── objectiveconditionsdialog.xrc │ │ ├── objectiveseditor.fbp │ │ ├── objectiveseditor.xrc │ │ ├── particleeditor.fbp │ │ ├── particleeditor.xrc │ │ ├── patchcreatedialog.fbp │ │ ├── patchcreatedialog.xrc │ │ ├── patchinspector.fbp │ │ ├── patchinspector.xrc │ │ ├── patchthickendialog.fbp │ │ ├── patchthickendialog.xrc │ │ ├── readableeditor.fbp │ │ ├── readableeditor.xrc │ │ ├── renderpreview.fbp │ │ ├── renderpreview.xrc │ │ ├── scatterdialog.fbp │ │ ├── scatterdialog.xrc │ │ ├── skineditor.fbp │ │ ├── skineditor.xrc │ │ ├── stimresponseeditor.fbp │ │ ├── stimresponseeditor.xrc │ │ ├── terraingenerator.fbp │ │ ├── terraingenerator.xrc │ │ ├── texturetoolmanipulationpanel.fbp │ │ ├── texturetoolmanipulationpanel.xrc │ │ ├── vcscommitdialog.fbp │ │ ├── vcscommitdialog.xrc │ │ ├── vcsstatusbar.fbp │ │ └── vcsstatusbar.xrc │ └── user.xml ├── install.cmake ├── libs/ │ ├── BasicTexture2D.h │ ├── BasicUndoMemento.h │ ├── DirectoryArchiveFile.h │ ├── EventRateLimiter.h │ ├── GameConfigUtil.h │ ├── KeyValueStore.h │ ├── ModelExportOptions.h │ ├── ObservedSelectable.h │ ├── ObservedUndoable.h │ ├── RGBAImage.h │ ├── RandomOrigin.h │ ├── Rectangle.h │ ├── SequentialTaskQueue.h │ ├── SurfaceShader.h │ ├── Transformable.h │ ├── UndoFileChangeTracker.h │ ├── VcsMapResourceStream.h │ ├── VersionControlLib.h │ ├── character.h │ ├── command/ │ │ ├── ExecutionFailure.h │ │ └── ExecutionNotPossible.h │ ├── debugging/ │ │ ├── ScenegraphUtils.h │ │ ├── ScopedDebugTimer.h │ │ ├── debugging.cpp │ │ ├── debugging.h │ │ ├── gl.h │ │ └── render.h │ ├── decl/ │ │ ├── DeclLib.h │ │ ├── DeclarationBase.h │ │ ├── DeclarationCreator.h │ │ └── EditableDeclaration.h │ ├── dragplanes.h │ ├── eclass.h │ ├── entitylib.h │ ├── gamelib.h │ ├── generic/ │ │ ├── Lazy.h │ │ └── callback.h │ ├── libfmt/ │ │ ├── LICENSE.rst │ │ └── fmt/ │ │ ├── args.h │ │ ├── chrono.h │ │ ├── color.h │ │ ├── compile.h │ │ ├── core.h │ │ ├── fmt.cc │ │ ├── format-inl.h │ │ ├── format.cc │ │ ├── format.h │ │ ├── os.cc │ │ ├── os.h │ │ ├── ostream.h │ │ ├── printf.h │ │ ├── ranges.h │ │ ├── std.h │ │ └── xchar.h │ ├── maplib.h │ ├── materials/ │ │ ├── FrobStageSetup.h │ │ └── ParseLib.h │ ├── math/ │ │ ├── AABB.cpp │ │ ├── AABB.h │ │ ├── CMakeLists.txt │ │ ├── FloatTools.h │ │ ├── Frustum.cpp │ │ ├── Frustum.h │ │ ├── Hash.h │ │ ├── Line.h │ │ ├── Matrix3.h │ │ ├── Matrix4.cpp │ │ ├── Matrix4.h │ │ ├── Plane3.cpp │ │ ├── Plane3.h │ │ ├── Quaternion.h │ │ ├── Ray.h │ │ ├── SHA256.cpp │ │ ├── SHA256.h │ │ ├── Segment.h │ │ ├── Vector2.h │ │ ├── Vector3.h │ │ ├── Vector4.h │ │ ├── ViewProjection.h │ │ ├── Viewer.h │ │ ├── XYZ.h │ │ ├── curve.h │ │ ├── eigen.h │ │ ├── lrint.h │ │ └── pi.h │ ├── messages/ │ │ ├── ApplicationIsActiveRequest.h │ │ ├── ApplicationShutdownRequest.h │ │ ├── AutomaticMapSaveRequest.h │ │ ├── ClearConsole.h │ │ ├── CommandExecutionFailed.h │ │ ├── ComponentSelectionModeToggleRequest.h │ │ ├── FileOverwriteConfirmation.h │ │ ├── FileSaveConfirmation.h │ │ ├── FileSelectionRequest.h │ │ ├── GameConfigNeededMessage.h │ │ ├── GridSnapRequest.h │ │ ├── LongRunningOperationMessage.h │ │ ├── ManipulatorModeToggleRequest.h │ │ ├── MapFileOperation.h │ │ ├── MapOperationMessage.h │ │ ├── NotificationMessage.h │ │ ├── ScopedLongRunningOperation.h │ │ ├── TextureChanged.h │ │ ├── TextureToolRequest.h │ │ └── UnselectSelectionRequest.h │ ├── module/ │ │ ├── ApplicationContextBase.cpp │ │ ├── ApplicationContextBase.h │ │ ├── CMakeLists.txt │ │ ├── CoreModule.cpp │ │ ├── CoreModule.h │ │ ├── DynamicLibrary.cpp │ │ ├── DynamicLibrary.h │ │ ├── StaticModule.cpp │ │ └── StaticModule.h │ ├── noise/ │ │ ├── Noise.h │ │ ├── PerlinNoise.h │ │ └── SimplexNoise.h │ ├── os/ │ │ ├── dir.h │ │ ├── file.h │ │ ├── fs.h │ │ └── path.h │ ├── parser/ │ │ ├── CodeTokeniser.h │ │ ├── DefBlockSyntaxParser.h │ │ ├── DefTokeniser.h │ │ ├── GuiTokeniser.h │ │ ├── ParseException.h │ │ ├── ThreadedDeclParser.h │ │ ├── ThreadedDefLoader.h │ │ └── Tokeniser.h │ ├── patch/ │ │ └── PatchIterators.h │ ├── pivot.h │ ├── pugixml/ │ │ ├── LICENSE │ │ ├── pugiconfig.hpp │ │ ├── pugixml.cpp │ │ └── pugixml.hpp │ ├── pybind/ │ │ ├── LICENSE │ │ └── pybind11/ │ │ ├── attr.h │ │ ├── buffer_info.h │ │ ├── cast.h │ │ ├── chrono.h │ │ ├── common.h │ │ ├── complex.h │ │ ├── detail/ │ │ │ ├── class.h │ │ │ ├── common.h │ │ │ ├── descr.h │ │ │ ├── init.h │ │ │ ├── internals.h │ │ │ ├── type_caster_base.h │ │ │ └── typeid.h │ │ ├── eigen.h │ │ ├── embed.h │ │ ├── eval.h │ │ ├── functional.h │ │ ├── gil.h │ │ ├── iostream.h │ │ ├── numpy.h │ │ ├── operators.h │ │ ├── options.h │ │ ├── pybind11.h │ │ ├── pytypes.h │ │ ├── stl/ │ │ │ └── filesystem.h │ │ ├── stl.h │ │ └── stl_bind.h │ ├── registry/ │ │ ├── CachedKey.h │ │ ├── Widgets.h │ │ ├── adaptors.h │ │ ├── buffer.h │ │ └── registry.h │ ├── render/ │ │ ├── CamRenderer.h │ │ ├── CameraView.h │ │ ├── Colour4.h │ │ ├── Colour4b.h │ │ ├── CompactWindingVertexBuffer.h │ │ ├── ContinuousBuffer.h │ │ ├── GeometryStore.h │ │ ├── IndexedVertexBuffer.h │ │ ├── MeshVertex.h │ │ ├── NopRenderView.h │ │ ├── NopVolumeTest.h │ │ ├── Rectangle.h │ │ ├── RenderVertex.h │ │ ├── RenderableBoundingBoxes.h │ │ ├── RenderableBox.h │ │ ├── RenderableCollectionWalker.h │ │ ├── RenderableCollectorBase.h │ │ ├── RenderableColouredBoundingBoxes.h │ │ ├── RenderableGeometry.h │ │ ├── RenderablePivot.h │ │ ├── RenderableSpacePartition.h │ │ ├── RenderableSurface.h │ │ ├── RenderableTextBase.h │ │ ├── RenderableVertexArray.h │ │ ├── SceneRenderWalker.h │ │ ├── StaticRenderableText.h │ │ ├── TexCoord2f.h │ │ ├── TextureToolView.h │ │ ├── VBO.h │ │ ├── Vertex3f.h │ │ ├── VertexBuffer.h │ │ ├── VertexCb.h │ │ ├── VertexHashing.h │ │ ├── VertexNCb.h │ │ ├── VertexNT.h │ │ ├── VertexTraits.h │ │ ├── View.h │ │ └── WindingRenderer.h │ ├── render.h │ ├── scene/ │ │ ├── AABBAccumulateWalker.h │ │ ├── AttachmentData.cpp │ │ ├── AttachmentData.h │ │ ├── BasicRootNode.h │ │ ├── CMakeLists.txt │ │ ├── ChildPrimitives.cpp │ │ ├── ChildPrimitives.h │ │ ├── Clone.h │ │ ├── ColourKey.h │ │ ├── Entity.cpp │ │ ├── Entity.h │ │ ├── EntityAttachment.h │ │ ├── EntityBreakdown.h │ │ ├── EntityClass.cpp │ │ ├── EntityClass.h │ │ ├── EntityKeyValue.cpp │ │ ├── EntityKeyValue.h │ │ ├── EntityNode.cpp │ │ ├── EntityNode.h │ │ ├── EntitySelector.h │ │ ├── EntitySettings.cpp │ │ ├── EntitySettings.h │ │ ├── Group.h │ │ ├── GroupNodeChecker.h │ │ ├── InstanceWalkers.cpp │ │ ├── InstanceWalkers.h │ │ ├── KeyObserverDelegate.h │ │ ├── KeyObserverMap.h │ │ ├── KeyValueObserver.cpp │ │ ├── KeyValueObserver.h │ │ ├── LayerUsageBreakdown.cpp │ │ ├── LayerUsageBreakdown.h │ │ ├── LayerValidityCheckWalker.h │ │ ├── ModelBreakdown.h │ │ ├── ModelFinder.cpp │ │ ├── ModelFinder.h │ │ ├── ModelKey.cpp │ │ ├── ModelKey.h │ │ ├── NameKey.h │ │ ├── NameKeyObserver.cpp │ │ ├── NameKeyObserver.h │ │ ├── NamespaceManager.cpp │ │ ├── NamespaceManager.h │ │ ├── Node.cpp │ │ ├── Node.h │ │ ├── OriginKey.h │ │ ├── PointTrace.h │ │ ├── PrefabBoundsAccumulator.h │ │ ├── RenderableEntityName.cpp │ │ ├── RenderableEntityName.h │ │ ├── RenderableObjectCollection.h │ │ ├── RenderableTargetLines.cpp │ │ ├── RenderableTargetLines.h │ │ ├── SelectableNode.cpp │ │ ├── SelectableNode.h │ │ ├── SelectionIndex.cpp │ │ ├── SelectionIndex.h │ │ ├── ShaderBreakdown.h │ │ ├── ShaderParms.cpp │ │ ├── ShaderParms.h │ │ ├── Target.h │ │ ├── TargetKey.cpp │ │ ├── TargetKey.h │ │ ├── TargetKeyCollection.cpp │ │ ├── TargetKeyCollection.h │ │ ├── TargetLineNode.cpp │ │ ├── TargetLineNode.h │ │ ├── TargetManager.cpp │ │ ├── TargetManager.h │ │ ├── TargetableNode.cpp │ │ ├── TargetableNode.h │ │ ├── TransformedCopy.h │ │ ├── TraversableNodeSet.cpp │ │ ├── TraversableNodeSet.h │ │ ├── Traverse.cpp │ │ ├── Traverse.h │ │ ├── filters/ │ │ │ ├── FilterGroup.cpp │ │ │ ├── FilterGroup.h │ │ │ ├── FilterRule.h │ │ │ ├── SceneFilter.cpp │ │ │ └── SceneFilter.h │ │ ├── merge/ │ │ │ ├── ComparisonResult.h │ │ │ ├── GraphComparer.cpp │ │ │ ├── GraphComparer.h │ │ │ ├── LayerMerger.h │ │ │ ├── LayerMergerBase.h │ │ │ ├── MergeAction.h │ │ │ ├── MergeActionNode.cpp │ │ │ ├── MergeActionNode.h │ │ │ ├── MergeLib.h │ │ │ ├── MergeOperation.cpp │ │ │ ├── MergeOperation.h │ │ │ ├── MergeOperationBase.cpp │ │ │ ├── MergeOperationBase.h │ │ │ ├── NodeUtils.h │ │ │ ├── SelectionGroupMerger.h │ │ │ ├── SelectionGroupMergerBase.h │ │ │ ├── ThreeWayLayerMerger.h │ │ │ ├── ThreeWayMergeOperation.cpp │ │ │ ├── ThreeWayMergeOperation.h │ │ │ └── ThreeWaySelectionGroupMerger.h │ │ ├── scene_fwd.h │ │ ├── shaders/ │ │ │ ├── NamedBindable.h │ │ │ ├── ShaderExpression.cpp │ │ │ └── ShaderExpression.h │ │ └── textures/ │ │ ├── HeightmapCreator.h │ │ ├── TextureManipulator.cpp │ │ └── TextureManipulator.h │ ├── scenelib.h │ ├── selection/ │ │ ├── BestPoint.h │ │ ├── CollectiveSpawnargs.h │ │ ├── Device.h │ │ ├── EntitiesFirstSelector.h │ │ ├── EntitySelection.h │ │ ├── OccludeSelector.h │ │ ├── Pivot2World.h │ │ ├── SelectedPlaneSet.h │ │ ├── SelectionPool.h │ │ ├── SelectionVolume.h │ │ └── SingleItemSelector.h │ ├── selectionlib.h │ ├── settings/ │ │ ├── MajorMinorVersion.h │ │ └── SettingsManager.h │ ├── shaderlib.h │ ├── splines/ │ │ ├── .cvsignore │ │ ├── math_angles.cpp │ │ ├── math_angles.h │ │ ├── math_matrix.cpp │ │ ├── math_matrix.h │ │ ├── math_quaternion.cpp │ │ ├── math_quaternion.h │ │ ├── math_vector.cpp │ │ ├── math_vector.h │ │ ├── q_parse.cpp │ │ ├── q_shared.cpp │ │ ├── q_shared.h │ │ ├── splines.cpp │ │ ├── splines.h │ │ ├── util_list.h │ │ ├── util_str.cpp │ │ └── util_str.h │ ├── stream/ │ │ ├── BinaryToTextInputStream.h │ │ ├── BufferInputStream.h │ │ ├── ExportStream.h │ │ ├── FileInputStream.h │ │ ├── MapResourceStream.h │ │ ├── PointerInputStream.h │ │ ├── ScopedArchiveBuffer.h │ │ ├── ScopedFileOutputStream.h │ │ ├── TemporaryOutputStream.h │ │ ├── TextFileInputStream.h │ │ ├── VcsMapResourceStream.h │ │ └── utils.h │ ├── string/ │ │ ├── case_conv.h │ │ ├── convert.h │ │ ├── encoding.h │ │ ├── format.h │ │ ├── join.h │ │ ├── predicate.h │ │ ├── replace.h │ │ ├── split.h │ │ ├── string.h │ │ ├── tokeniser.h │ │ └── trim.h │ ├── texturelib.h │ ├── time/ │ │ ├── ScopeTimer.h │ │ ├── StopWatch.h │ │ └── Timer.h │ ├── transformlib.h │ ├── util/ │ │ ├── Noncopyable.h │ │ └── ScopedBoolLock.h │ ├── wxutil/ │ │ ├── Bitmap.h │ │ ├── BitmapToggleButton.h │ │ ├── Button.h │ │ ├── CMakeLists.txt │ │ ├── ChoiceHelper.h │ │ ├── ConsoleView.cpp │ │ ├── ConsoleView.h │ │ ├── ControlButton.h │ │ ├── Debug.h │ │ ├── DeferredMotionDelta.h │ │ ├── DirChooser.cpp │ │ ├── DirChooser.h │ │ ├── DockablePanel.h │ │ ├── EntityClassChooser.cpp │ │ ├── EntityClassChooser.h │ │ ├── EntryAbortedException.h │ │ ├── FileChooser.cpp │ │ ├── FileChooser.h │ │ ├── FormLayout.h │ │ ├── FreezePointer.cpp │ │ ├── FreezePointer.h │ │ ├── GLContext.h │ │ ├── GLWidget.cpp │ │ ├── GLWidget.h │ │ ├── IConv.h │ │ ├── Icon.h │ │ ├── ModalProgressDialog.cpp │ │ ├── ModalProgressDialog.h │ │ ├── Modifier.h │ │ ├── MouseButton.h │ │ ├── MouseToolHandler.cpp │ │ ├── MouseToolHandler.h │ │ ├── MultiMonitor.h │ │ ├── NonModalEntry.h │ │ ├── PanedPosition.cpp │ │ ├── PanedPosition.h │ │ ├── PathEntry.cpp │ │ ├── PathEntry.h │ │ ├── ScopeTimer.h │ │ ├── ScrollWindow.h │ │ ├── SerialisableWidgets.cpp │ │ ├── SerialisableWidgets.h │ │ ├── Splitter.cpp │ │ ├── Splitter.h │ │ ├── TransientPopupWindow.h │ │ ├── WindowPosition.cpp │ │ ├── WindowPosition.h │ │ ├── WindowState.cpp │ │ ├── WindowState.h │ │ ├── XmlResourceBasedWidget.h │ │ ├── dataview/ │ │ │ ├── DeclarationTreeView.cpp │ │ │ ├── DeclarationTreeView.h │ │ │ ├── IResourceTreePopulator.h │ │ │ ├── IndicatorColumn.h │ │ │ ├── KeyValueTable.cpp │ │ │ ├── KeyValueTable.h │ │ │ ├── ResourceTreeView.cpp │ │ │ ├── ResourceTreeView.h │ │ │ ├── ResourceTreeViewToolbar.cpp │ │ │ ├── ResourceTreeViewToolbar.h │ │ │ ├── ThreadedDeclarationTreePopulator.h │ │ │ ├── ThreadedResourceTreePopulator.cpp │ │ │ ├── ThreadedResourceTreePopulator.h │ │ │ ├── TreeModel.cpp │ │ │ ├── TreeModel.h │ │ │ ├── TreeModelFilter.cpp │ │ │ ├── TreeModelFilter.h │ │ │ ├── TreeView.cpp │ │ │ ├── TreeView.h │ │ │ ├── TreeViewItemStyle.h │ │ │ ├── VFSTreePopulator.cpp │ │ │ └── VFSTreePopulator.h │ │ ├── decl/ │ │ │ ├── DeclFileInfo.h │ │ │ ├── DeclarationSelector.cpp │ │ │ ├── DeclarationSelector.h │ │ │ ├── DeclarationSelectorDialog.cpp │ │ │ └── DeclarationSelectorDialog.h │ │ ├── dialog/ │ │ │ ├── AutoSaveRequestBlocker.h │ │ │ ├── Dialog.cpp │ │ │ ├── Dialog.h │ │ │ ├── DialogBase.cpp │ │ │ ├── DialogBase.h │ │ │ ├── DialogElements.h │ │ │ ├── MessageBox.cpp │ │ │ ├── MessageBox.h │ │ │ └── ScrollEventPropagationFilter.h │ │ ├── event/ │ │ │ ├── KeyEventFilter.h │ │ │ └── SingleIdleCallback.h │ │ ├── fsview/ │ │ │ ├── FileSystemView.cpp │ │ │ ├── FileSystemView.h │ │ │ ├── Populator.cpp │ │ │ └── Populator.h │ │ ├── menu/ │ │ │ ├── CommandMenuItem.h │ │ │ ├── FilterPopupMenu.cpp │ │ │ ├── FilterPopupMenu.h │ │ │ ├── IconTextMenuItem.h │ │ │ ├── MenuItem.h │ │ │ ├── PopupMenu.cpp │ │ │ ├── PopupMenu.h │ │ │ └── SeparatorItem.h │ │ ├── preview/ │ │ │ ├── EntityClassPreview.h │ │ │ ├── EntityPreview.cpp │ │ │ ├── EntityPreview.h │ │ │ ├── GuiRenderer.cpp │ │ │ ├── GuiRenderer.h │ │ │ ├── GuiView.cpp │ │ │ ├── GuiView.h │ │ │ ├── ModelPreview.cpp │ │ │ ├── ModelPreview.h │ │ │ ├── ParticlePreview.cpp │ │ │ ├── ParticlePreview.h │ │ │ ├── RenderPreview.cpp │ │ │ ├── RenderPreview.h │ │ │ └── SkinPreview.h │ │ └── sourceview/ │ │ ├── DeclarationSourceView.cpp │ │ ├── DeclarationSourceView.h │ │ ├── DefinitionView.cpp │ │ ├── DefinitionView.h │ │ ├── SourceView.cpp │ │ └── SourceView.h │ └── xmlutil/ │ ├── CMakeLists.txt │ ├── Document.cpp │ ├── Document.h │ ├── InvalidNodeException.h │ ├── MissingXMLNodeException.h │ ├── Node.cpp │ ├── Node.h │ └── XPathException.h ├── man/ │ ├── darkradiant.1 │ └── darkradiant.adoc ├── plugins/ │ ├── dm.conversation/ │ │ ├── ActorNodeFinder.h │ │ ├── CMakeLists.txt │ │ ├── CommandArgumentItem.cpp │ │ ├── CommandArgumentItem.h │ │ ├── CommandEditor.cpp │ │ ├── CommandEditor.h │ │ ├── Conversation.h │ │ ├── ConversationCommand.cpp │ │ ├── ConversationCommand.h │ │ ├── ConversationCommandInfo.cpp │ │ ├── ConversationCommandInfo.h │ │ ├── ConversationCommandLibrary.cpp │ │ ├── ConversationCommandLibrary.h │ │ ├── ConversationDialog.cpp │ │ ├── ConversationDialog.h │ │ ├── ConversationEditor.cpp │ │ ├── ConversationEditor.h │ │ ├── ConversationEntity.cpp │ │ ├── ConversationEntity.h │ │ ├── ConversationEntityFinder.h │ │ ├── ConversationKeyExtractor.cpp │ │ ├── ConversationKeyExtractor.h │ │ └── plugin.cpp │ ├── dm.difficulty/ │ │ ├── CMakeLists.txt │ │ ├── ClassNameStore.cpp │ │ ├── ClassNameStore.h │ │ ├── DifficultyDialog.cpp │ │ ├── DifficultyDialog.h │ │ ├── DifficultyEditor.cpp │ │ ├── DifficultyEditor.h │ │ ├── DifficultyEntity.cpp │ │ ├── DifficultyEntity.h │ │ ├── DifficultyEntityFinder.h │ │ ├── DifficultySettings.cpp │ │ ├── DifficultySettings.h │ │ ├── DifficultySettingsManager.cpp │ │ ├── DifficultySettingsManager.h │ │ ├── Setting.cpp │ │ ├── Setting.h │ │ └── plugin.cpp │ ├── dm.editing/ │ │ ├── AIEditingControl.h │ │ ├── AIEditingPanel.cpp │ │ ├── AIEditingPanel.h │ │ ├── AIHeadChooserDialog.cpp │ │ ├── AIHeadChooserDialog.h │ │ ├── AIHeadPropertyEditor.cpp │ │ ├── AIHeadPropertyEditor.h │ │ ├── AIVocalSetChooserDialog.cpp │ │ ├── AIVocalSetChooserDialog.h │ │ ├── AIVocalSetPreview.cpp │ │ ├── AIVocalSetPreview.h │ │ ├── AIVocalSetPropertyEditor.cpp │ │ ├── AIVocalSetPropertyEditor.h │ │ ├── CMakeLists.txt │ │ ├── DarkmodTxt.cpp │ │ ├── DarkmodTxt.h │ │ ├── DeprecatedEclassCollector.h │ │ ├── FixupMap.cpp │ │ ├── FixupMap.h │ │ ├── FixupMapDialog.cpp │ │ ├── FixupMapDialog.h │ │ ├── MissionInfoEditDialog.cpp │ │ ├── MissionInfoEditDialog.h │ │ ├── MissionInfoGuiView.cpp │ │ ├── MissionInfoGuiView.h │ │ ├── MissionInfoTextFile.cpp │ │ ├── MissionInfoTextFile.h │ │ ├── MissionReadmeDialog.cpp │ │ ├── MissionReadmeDialog.h │ │ ├── ReadmeTxt.cpp │ │ ├── ReadmeTxt.h │ │ ├── ShaderReplacer.h │ │ ├── SpawnargLinkedCheckbox.h │ │ ├── SpawnargLinkedSpinButton.h │ │ ├── SpawnargReplacer.h │ │ ├── ThreadedEntityDefPopulator.h │ │ └── plugin.cpp │ ├── dm.gameconnection/ │ │ ├── AutomationEngine.cpp │ │ ├── AutomationEngine.h │ │ ├── CMakeLists.txt │ │ ├── DiffDoom3MapWriter.cpp │ │ ├── DiffDoom3MapWriter.h │ │ ├── DiffStatus.h │ │ ├── GameConnection.cpp │ │ ├── GameConnection.h │ │ ├── GameConnectionControl.h │ │ ├── GameConnectionPanel.cpp │ │ ├── GameConnectionPanel.h │ │ ├── MapObserver.cpp │ │ ├── MapObserver.h │ │ ├── MessageTcp.cpp │ │ ├── MessageTcp.h │ │ └── clsocket/ │ │ ├── ActiveSocket.cpp │ │ ├── ActiveSocket.h │ │ ├── Host.h │ │ ├── PassiveSocket.cpp │ │ ├── PassiveSocket.h │ │ ├── SimpleSocket.cpp │ │ ├── SimpleSocket.h │ │ ├── StatTimer.h │ │ └── readme.txt │ ├── dm.gui/ │ │ ├── CMakeLists.txt │ │ ├── GuiSelector.cpp │ │ ├── GuiSelector.h │ │ ├── ReadableEditorDialog.cpp │ │ ├── ReadableEditorDialog.h │ │ ├── ReadableGuiView.cpp │ │ ├── ReadableGuiView.h │ │ ├── ReadablePopulator.h │ │ ├── ReadableReloader.h │ │ ├── TextViewInfoDialog.h │ │ ├── XData.cpp │ │ ├── XData.h │ │ ├── XDataLoader.cpp │ │ ├── XDataLoader.h │ │ ├── XDataSelector.cpp │ │ ├── XDataSelector.h │ │ ├── XdFileChooserDialog.cpp │ │ ├── XdFileChooserDialog.h │ │ ├── gui/ │ │ │ ├── Gui.cpp │ │ │ ├── Gui.h │ │ │ ├── GuiExpression.cpp │ │ │ ├── GuiExpression.h │ │ │ ├── GuiManager.cpp │ │ │ ├── GuiManager.h │ │ │ ├── GuiScript.cpp │ │ │ ├── GuiScript.h │ │ │ ├── GuiWindowDef.cpp │ │ │ ├── GuiWindowDef.h │ │ │ ├── RenderableCharacterBatch.cpp │ │ │ ├── RenderableCharacterBatch.h │ │ │ ├── RenderableText.cpp │ │ │ ├── RenderableText.h │ │ │ ├── TextParts.h │ │ │ ├── Variable.cpp │ │ │ └── Variable.h │ │ └── plugin.cpp │ ├── dm.objectives/ │ │ ├── CMakeLists.txt │ │ ├── Component.cpp │ │ ├── Component.h │ │ ├── ComponentType.cpp │ │ ├── ComponentType.h │ │ ├── ComponentsDialog.cpp │ │ ├── ComponentsDialog.h │ │ ├── DifficultyPanel.cpp │ │ ├── DifficultyPanel.h │ │ ├── Logic.h │ │ ├── LogicEditor.cpp │ │ ├── LogicEditor.h │ │ ├── MissionLogicDialog.cpp │ │ ├── MissionLogicDialog.h │ │ ├── Objective.h │ │ ├── ObjectiveCondition.h │ │ ├── ObjectiveConditionsDialog.cpp │ │ ├── ObjectiveConditionsDialog.h │ │ ├── ObjectiveEntity.cpp │ │ ├── ObjectiveEntity.h │ │ ├── ObjectiveEntityFinder.cpp │ │ ├── ObjectiveEntityFinder.h │ │ ├── ObjectiveKeyExtractor.cpp │ │ ├── ObjectiveKeyExtractor.h │ │ ├── ObjectivesEditor.cpp │ │ ├── ObjectivesEditor.h │ │ ├── Specifier.cpp │ │ ├── Specifier.h │ │ ├── SpecifierType.cpp │ │ ├── SpecifierType.h │ │ ├── TargetList.h │ │ ├── ce/ │ │ │ ├── AIFindBodyComponentEditor.cpp │ │ │ ├── AIFindBodyComponentEditor.h │ │ │ ├── AIFindItemComponentEditor.cpp │ │ │ ├── AIFindItemComponentEditor.h │ │ │ ├── AlertComponentEditor.cpp │ │ │ ├── AlertComponentEditor.h │ │ │ ├── ComponentEditor.h │ │ │ ├── ComponentEditorBase.h │ │ │ ├── ComponentEditorFactory.cpp │ │ │ ├── ComponentEditorFactory.h │ │ │ ├── CustomClockedComponentEditor.cpp │ │ │ ├── CustomClockedComponentEditor.h │ │ │ ├── CustomComponentEditor.cpp │ │ │ ├── CustomComponentEditor.h │ │ │ ├── DestroyComponentEditor.cpp │ │ │ ├── DestroyComponentEditor.h │ │ │ ├── DistanceComponentEditor.cpp │ │ │ ├── DistanceComponentEditor.h │ │ │ ├── InfoLocationComponentEditor.cpp │ │ │ ├── InfoLocationComponentEditor.h │ │ │ ├── ItemComponentEditor.cpp │ │ │ ├── ItemComponentEditor.h │ │ │ ├── KillComponentEditor.cpp │ │ │ ├── KillComponentEditor.h │ │ │ ├── KnockoutComponentEditor.cpp │ │ │ ├── KnockoutComponentEditor.h │ │ │ ├── LocationComponentEditor.cpp │ │ │ ├── LocationComponentEditor.h │ │ │ ├── PickpocketComponentEditor.cpp │ │ │ ├── PickpocketComponentEditor.h │ │ │ ├── ReadableClosedComponentEditor.cpp │ │ │ ├── ReadableClosedComponentEditor.h │ │ │ ├── ReadableOpenedComponentEditor.cpp │ │ │ ├── ReadableOpenedComponentEditor.h │ │ │ ├── ReadablePageReachedComponentEditor.cpp │ │ │ ├── ReadablePageReachedComponentEditor.h │ │ │ ├── SpecifierEditCombo.cpp │ │ │ ├── SpecifierEditCombo.h │ │ │ └── specpanel/ │ │ │ ├── AIInnocenceSpecifierPanel.cpp │ │ │ ├── AIInnocenceSpecifierPanel.h │ │ │ ├── AITeamSpecifierPanel.cpp │ │ │ ├── AITeamSpecifierPanel.h │ │ │ ├── AITypeSpecifierPanel.cpp │ │ │ ├── AITypeSpecifierPanel.h │ │ │ ├── ClassnameSpecifierPanel.cpp │ │ │ ├── ClassnameSpecifierPanel.h │ │ │ ├── EntityNameSpecifierPanel.cpp │ │ │ ├── EntityNameSpecifierPanel.h │ │ │ ├── GroupSpecifierPanel.cpp │ │ │ ├── GroupSpecifierPanel.h │ │ │ ├── SpawnClassSpecifierPanel.cpp │ │ │ ├── SpawnClassSpecifierPanel.h │ │ │ ├── SpecifierPanel.h │ │ │ ├── SpecifierPanelFactory.cpp │ │ │ ├── SpecifierPanelFactory.h │ │ │ ├── TextSpecifierPanel.cpp │ │ │ └── TextSpecifierPanel.h │ │ ├── objectives.cpp │ │ ├── precompiled.cpp │ │ ├── precompiled.h │ │ └── util/ │ │ ├── ObjectivesException.h │ │ └── TwoColumnTextCombo.h │ ├── dm.stimresponse/ │ │ ├── CMakeLists.txt │ │ ├── ClassEditor.cpp │ │ ├── ClassEditor.h │ │ ├── CustomStimEditor.cpp │ │ ├── CustomStimEditor.h │ │ ├── EffectArgumentItem.cpp │ │ ├── EffectArgumentItem.h │ │ ├── EffectEditor.cpp │ │ ├── EffectEditor.h │ │ ├── ResponseEditor.cpp │ │ ├── ResponseEditor.h │ │ ├── ResponseEffect.cpp │ │ ├── ResponseEffect.h │ │ ├── ResponseEffectTypes.cpp │ │ ├── ResponseEffectTypes.h │ │ ├── SREntity.cpp │ │ ├── SREntity.h │ │ ├── SRPropertyLoader.cpp │ │ ├── SRPropertyLoader.h │ │ ├── SRPropertyRemover.cpp │ │ ├── SRPropertyRemover.h │ │ ├── SRPropertySaver.cpp │ │ ├── SRPropertySaver.h │ │ ├── StimEditor.cpp │ │ ├── StimEditor.h │ │ ├── StimResponse.cpp │ │ ├── StimResponse.h │ │ ├── StimResponseEditor.cpp │ │ ├── StimResponseEditor.h │ │ ├── StimTypes.cpp │ │ ├── StimTypes.h │ │ ├── plugin.cpp │ │ ├── precompiled.cpp │ │ └── precompiled.h │ ├── script/ │ │ ├── CMakeLists.txt │ │ ├── PythonConsoleWriter.h │ │ ├── PythonModule.cpp │ │ ├── PythonModule.h │ │ ├── SceneNodeBuffer.cpp │ │ ├── SceneNodeBuffer.h │ │ ├── ScriptCommand.cpp │ │ ├── ScriptCommand.h │ │ ├── ScriptModule.cpp │ │ ├── ScriptingSystem.cpp │ │ ├── ScriptingSystem.h │ │ ├── interfaces/ │ │ │ ├── BrushInterface.cpp │ │ │ ├── BrushInterface.h │ │ │ ├── CameraInterface.cpp │ │ │ ├── CameraInterface.h │ │ │ ├── CommandSystemInterface.cpp │ │ │ ├── CommandSystemInterface.h │ │ │ ├── DeclarationManagerInterface.cpp │ │ │ ├── DeclarationManagerInterface.h │ │ │ ├── DialogInterface.cpp │ │ │ ├── DialogInterface.h │ │ │ ├── EClassInterface.cpp │ │ │ ├── EClassInterface.h │ │ │ ├── EntityInterface.cpp │ │ │ ├── EntityInterface.h │ │ │ ├── FileSystemInterface.cpp │ │ │ ├── FileSystemInterface.h │ │ │ ├── FxManagerInterface.cpp │ │ │ ├── FxManagerInterface.h │ │ │ ├── GameInterface.cpp │ │ │ ├── GameInterface.h │ │ │ ├── GridInterface.cpp │ │ │ ├── GridInterface.h │ │ │ ├── LayerInterface.cpp │ │ │ ├── LayerInterface.h │ │ │ ├── MapInterface.cpp │ │ │ ├── MapInterface.h │ │ │ ├── MathInterface.cpp │ │ │ ├── MathInterface.h │ │ │ ├── ModelInterface.cpp │ │ │ ├── ModelInterface.h │ │ │ ├── PatchInterface.cpp │ │ │ ├── PatchInterface.h │ │ │ ├── RadiantInterface.cpp │ │ │ ├── RadiantInterface.h │ │ │ ├── RegistryInterface.h │ │ │ ├── SceneGraphInterface.cpp │ │ │ ├── SceneGraphInterface.h │ │ │ ├── SelectionGroupInterface.cpp │ │ │ ├── SelectionGroupInterface.h │ │ │ ├── SelectionInterface.cpp │ │ │ ├── SelectionInterface.h │ │ │ ├── SelectionSetInterface.cpp │ │ │ ├── SelectionSetInterface.h │ │ │ ├── ShaderSystemInterface.cpp │ │ │ ├── ShaderSystemInterface.h │ │ │ ├── SkinInterface.cpp │ │ │ ├── SkinInterface.h │ │ │ ├── SoundInterface.cpp │ │ │ └── SoundInterface.h │ │ ├── precompiled.cpp │ │ └── precompiled.h │ ├── sound/ │ │ ├── CMakeLists.txt │ │ ├── OggFileLoader.h │ │ ├── OggFileStream.h │ │ ├── SoundManager.cpp │ │ ├── SoundManager.h │ │ ├── SoundPlayer.cpp │ │ ├── SoundPlayer.h │ │ ├── SoundShader.cpp │ │ ├── SoundShader.h │ │ ├── WavFileLoader.h │ │ └── sound.cpp │ └── vcs/ │ ├── Algorithm.h │ ├── CMakeLists.txt │ ├── Commit.h │ ├── CommitMetadata.h │ ├── CredentialManager.h │ ├── Diff.h │ ├── GitArchiveTextFile.h │ ├── GitException.h │ ├── GitModule.cpp │ ├── GitModule.h │ ├── Index.cpp │ ├── Index.h │ ├── Reference.h │ ├── Remote.h │ ├── Repository.cpp │ ├── Repository.h │ ├── Signature.h │ ├── Tree.h │ └── ui/ │ ├── CommitDialog.h │ ├── VcsStatus.cpp │ └── VcsStatus.h ├── radiant/ │ ├── ApplicationContext.h │ ├── CMakeLists.txt │ ├── RadiantApp.cpp │ ├── RadiantApp.h │ ├── camera/ │ │ ├── CamWnd.cpp │ │ ├── CamWnd.h │ │ ├── CameraSettings.cpp │ │ ├── CameraSettings.h │ │ ├── CameraWndManager.cpp │ │ ├── CameraWndManager.h │ │ ├── FloorHeightWalker.h │ │ └── tools/ │ │ ├── CameraMouseToolEvent.h │ │ ├── DecalShooterTool.cpp │ │ ├── DecalShooterTool.h │ │ ├── FaceIntersectionFinder.cpp │ │ ├── FaceIntersectionFinder.h │ │ ├── FreeMoveTool.h │ │ ├── JumpToObjectTool.h │ │ ├── ObjectFinder.h │ │ ├── PanViewTool.h │ │ └── ShaderClipboardTools.h │ ├── clipboard/ │ │ ├── ClipboardModule.cpp │ │ └── ClipboardModule.h │ ├── darkradiant.rc │ ├── eventmanager/ │ │ ├── Accelerator.cpp │ │ ├── Accelerator.h │ │ ├── Event.h │ │ ├── EventManager.cpp │ │ ├── EventManager.h │ │ ├── GlobalKeyEventFilter.cpp │ │ ├── GlobalKeyEventFilter.h │ │ ├── KeyEvent.h │ │ ├── ModifierHintPopup.h │ │ ├── MouseToolGroup.cpp │ │ ├── MouseToolGroup.h │ │ ├── MouseToolManager.cpp │ │ ├── MouseToolManager.h │ │ ├── RegistryToggle.h │ │ ├── ShortcutSaver.h │ │ ├── Statement.cpp │ │ ├── Statement.h │ │ ├── Toggle.cpp │ │ ├── Toggle.h │ │ ├── WidgetToggle.cpp │ │ └── WidgetToggle.h │ ├── log/ │ │ ├── PIDFile.h │ │ └── PopupErrorHandler.h │ ├── main.cpp │ ├── map/ │ │ ├── AutoSaveTimer.cpp │ │ ├── AutoSaveTimer.h │ │ ├── StartupMapLoader.cpp │ │ └── StartupMapLoader.h │ ├── precompiled.cpp │ ├── precompiled.h │ ├── render/ │ │ └── RenderStatistics.h │ ├── selection/ │ │ ├── ManipulateMouseTool.cpp │ │ ├── ManipulateMouseTool.h │ │ ├── SceneManipulateMouseTool.cpp │ │ ├── SceneManipulateMouseTool.h │ │ ├── SelectionMouseTools.cpp │ │ └── SelectionMouseTools.h │ ├── settings/ │ │ ├── LocalisationModule.cpp │ │ ├── LocalisationModule.h │ │ ├── LocalisationProvider.cpp │ │ ├── LocalisationProvider.h │ │ ├── Win32Registry.cpp │ │ └── Win32Registry.h │ ├── textool/ │ │ ├── TexTool.cpp │ │ ├── TexTool.h │ │ ├── TexToolModeToggles.h │ │ ├── TextureToolControl.h │ │ └── tools/ │ │ ├── TextureToolCycleSelectionTool.h │ │ ├── TextureToolManipulateMouseTool.cpp │ │ ├── TextureToolManipulateMouseTool.h │ │ ├── TextureToolMouseEvent.h │ │ └── TextureToolSelectionTool.h │ ├── ui/ │ │ ├── AutoSaveRequestHandler.h │ │ ├── DispatchEvent.cpp │ │ ├── DispatchEvent.h │ │ ├── Documentation.cpp │ │ ├── Documentation.h │ │ ├── FileOverwriteConfirmationHandler.h │ │ ├── FileSaveConfirmationHandler.h │ │ ├── FileSelectionRequestHandler.h │ │ ├── LongRunningOperationHandler.cpp │ │ ├── LongRunningOperationHandler.h │ │ ├── ManipulatorToggle.h │ │ ├── MapCommands.cpp │ │ ├── MapCommands.h │ │ ├── MapFileProgressHandler.cpp │ │ ├── MapFileProgressHandler.h │ │ ├── PointFileChooser.cpp │ │ ├── PointFileChooser.h │ │ ├── SelectionModeToggle.h │ │ ├── UserInterfaceModule.cpp │ │ ├── UserInterfaceModule.h │ │ ├── aas/ │ │ │ ├── AasFileControl.cpp │ │ │ ├── AasFileControl.h │ │ │ ├── AasVisualisationControl.h │ │ │ ├── AasVisualisationPanel.cpp │ │ │ ├── AasVisualisationPanel.h │ │ │ ├── RenderableAasFile.cpp │ │ │ └── RenderableAasFile.h │ │ ├── about/ │ │ │ ├── AboutDialog.cpp │ │ │ └── AboutDialog.h │ │ ├── animationpreview/ │ │ │ ├── AnimationPreview.cpp │ │ │ ├── AnimationPreview.h │ │ │ ├── MD5AnimationChooser.cpp │ │ │ ├── MD5AnimationChooser.h │ │ │ ├── MD5AnimationViewer.cpp │ │ │ └── MD5AnimationViewer.h │ │ ├── array/ │ │ │ ├── ArrayDialog.cpp │ │ │ └── ArrayDialog.h │ │ ├── brush/ │ │ │ ├── CreateTrimDialog.cpp │ │ │ ├── CreateTrimDialog.h │ │ │ ├── FindBrush.cpp │ │ │ ├── FindBrush.h │ │ │ ├── QuerySidesDialog.cpp │ │ │ └── QuerySidesDialog.h │ │ ├── colourscheme/ │ │ │ ├── ColourSchemeEditor.cpp │ │ │ └── ColourSchemeEditor.h │ │ ├── commandlist/ │ │ │ ├── CommandList.cpp │ │ │ ├── CommandList.h │ │ │ ├── CommandListPopulator.h │ │ │ ├── ShortcutChooser.cpp │ │ │ └── ShortcutChooser.h │ │ ├── common/ │ │ │ ├── DialogManager.cpp │ │ │ ├── DialogManager.h │ │ │ ├── EntityChooser.cpp │ │ │ ├── EntityChooser.h │ │ │ ├── ImageFilePopulator.cpp │ │ │ ├── ImageFilePopulator.h │ │ │ ├── ImageFileSelector.cpp │ │ │ ├── ImageFileSelector.h │ │ │ ├── MapPreview.cpp │ │ │ ├── MapPreview.h │ │ │ ├── SkinChooser.cpp │ │ │ ├── SkinChooser.h │ │ │ ├── SoundChooser.cpp │ │ │ ├── SoundChooser.h │ │ │ ├── SoundShaderPreview.cpp │ │ │ ├── SoundShaderPreview.h │ │ │ ├── SoundShaderSelector.h │ │ │ ├── TexturePreviewCombo.cpp │ │ │ └── TexturePreviewCombo.h │ │ ├── console/ │ │ │ ├── CommandEntry.cpp │ │ │ ├── CommandEntry.h │ │ │ ├── Console.cpp │ │ │ ├── Console.h │ │ │ └── ConsoleControl.h │ │ ├── decalshooter/ │ │ │ ├── DecalShooterControl.h │ │ │ ├── DecalShooterPanel.cpp │ │ │ └── DecalShooterPanel.h │ │ ├── eclasstree/ │ │ │ ├── EClassTree.cpp │ │ │ ├── EClassTree.h │ │ │ ├── EClassTreeBuilder.cpp │ │ │ └── EClassTreeBuilder.h │ │ ├── einspector/ │ │ │ ├── AddPropertyDialog.cpp │ │ │ ├── AddPropertyDialog.h │ │ │ ├── Algorithm.cpp │ │ │ ├── Algorithm.h │ │ │ ├── AnglePropertyEditor.cpp │ │ │ ├── AnglePropertyEditor.h │ │ │ ├── BooleanPropertyEditor.cpp │ │ │ ├── BooleanPropertyEditor.h │ │ │ ├── ClassnamePropertyEditor.cpp │ │ │ ├── ClassnamePropertyEditor.h │ │ │ ├── ColourPropertyEditor.cpp │ │ │ ├── ColourPropertyEditor.h │ │ │ ├── EntityInspector.cpp │ │ │ ├── EntityInspector.h │ │ │ ├── EntityInspectorModule.cpp │ │ │ ├── EntityInspectorModule.h │ │ │ ├── EntityPropertyEditor.cpp │ │ │ ├── EntityPropertyEditor.h │ │ │ ├── FloatPropertyEditor.cpp │ │ │ ├── FloatPropertyEditor.h │ │ │ ├── FxPropertyEditor.cpp │ │ │ ├── FxPropertyEditor.h │ │ │ ├── InheritPropertyEditor.cpp │ │ │ ├── InheritPropertyEditor.h │ │ │ ├── ModelPropertyEditor.cpp │ │ │ ├── ModelPropertyEditor.h │ │ │ ├── PropertyEditor.cpp │ │ │ ├── PropertyEditor.h │ │ │ ├── PropertyEditorFactory.cpp │ │ │ ├── PropertyEditorFactory.h │ │ │ ├── SkinPropertyEditor.cpp │ │ │ ├── SkinPropertyEditor.h │ │ │ ├── SoundPropertyEditor.cpp │ │ │ ├── SoundPropertyEditor.h │ │ │ ├── TargetKey.h │ │ │ ├── TexturePropertyEditor.cpp │ │ │ ├── TexturePropertyEditor.h │ │ │ ├── Vector3PropertyEditor.cpp │ │ │ └── Vector3PropertyEditor.h │ │ ├── entitylist/ │ │ │ ├── EntityList.cpp │ │ │ ├── EntityList.h │ │ │ ├── EntityListControl.h │ │ │ ├── GraphTreeModel.cpp │ │ │ ├── GraphTreeModel.h │ │ │ ├── GraphTreeModelPopulator.h │ │ │ └── GraphTreeNode.h │ │ ├── favourites/ │ │ │ ├── FavouritesBrowser.cpp │ │ │ ├── FavouritesBrowser.h │ │ │ ├── FavouritesBrowserControl.h │ │ │ └── FavouritesUserInterfaceModule.cpp │ │ ├── filters/ │ │ │ ├── FilterContextMenu.cpp │ │ │ ├── FilterContextMenu.h │ │ │ ├── FilterOrthoContextMenuItem.cpp │ │ │ ├── FilterOrthoContextMenuItem.h │ │ │ ├── FilterUserInterface.cpp │ │ │ ├── FilterUserInterface.h │ │ │ ├── FiltersMainMenu.cpp │ │ │ ├── FiltersMainMenu.h │ │ │ └── editor/ │ │ │ ├── Filter.h │ │ │ ├── FilterDialog.cpp │ │ │ ├── FilterDialog.h │ │ │ ├── FilterEditor.cpp │ │ │ └── FilterEditor.h │ │ ├── findshader/ │ │ │ ├── FindShader.cpp │ │ │ ├── FindShader.h │ │ │ └── FindShaderControl.h │ │ ├── fx/ │ │ │ ├── FxChooser.cpp │ │ │ └── FxChooser.h │ │ ├── gl/ │ │ │ ├── WxGLWidgetManager.cpp │ │ │ └── WxGLWidgetManager.h │ │ ├── grid/ │ │ │ ├── GridUserInterface.cpp │ │ │ └── GridUserInterface.h │ │ ├── layers/ │ │ │ ├── CreateLayerDialog.cpp │ │ │ ├── CreateLayerDialog.h │ │ │ ├── LayerContextMenu.cpp │ │ │ ├── LayerContextMenu.h │ │ │ ├── LayerControl.h │ │ │ ├── LayerControlPanel.cpp │ │ │ ├── LayerControlPanel.h │ │ │ ├── LayerOrthoContextMenuItem.cpp │ │ │ └── LayerOrthoContextMenuItem.h │ │ ├── lightinspector/ │ │ │ ├── LightInspector.cpp │ │ │ ├── LightInspector.h │ │ │ └── LightInspectorControl.h │ │ ├── mainframe/ │ │ │ ├── AuiFloatingFrame.cpp │ │ │ ├── AuiFloatingFrame.h │ │ │ ├── AuiLayout.cpp │ │ │ ├── AuiLayout.h │ │ │ ├── AuiManager.cpp │ │ │ ├── AuiManager.h │ │ │ ├── MainFrame.cpp │ │ │ ├── MainFrame.h │ │ │ ├── PropertyNotebook.cpp │ │ │ ├── PropertyNotebook.h │ │ │ ├── ScreenUpdateBlocker.cpp │ │ │ ├── ScreenUpdateBlocker.h │ │ │ ├── TopLevelFrame.cpp │ │ │ ├── TopLevelFrame.h │ │ │ ├── ViewMenu.cpp │ │ │ └── ViewMenu.h │ │ ├── mapinfo/ │ │ │ ├── EntityInfoTab.cpp │ │ │ ├── EntityInfoTab.h │ │ │ ├── LayerInfoTab.cpp │ │ │ ├── LayerInfoTab.h │ │ │ ├── MapInfoDialog.cpp │ │ │ ├── MapInfoDialog.h │ │ │ ├── ModelInfoTab.cpp │ │ │ ├── ModelInfoTab.h │ │ │ ├── ShaderInfoTab.cpp │ │ │ └── ShaderInfoTab.h │ │ ├── mapselector/ │ │ │ ├── MapSelector.cpp │ │ │ └── MapSelector.h │ │ ├── materials/ │ │ │ ├── MaterialChooser.cpp │ │ │ ├── MaterialChooser.h │ │ │ ├── MaterialPopulator.cpp │ │ │ ├── MaterialPopulator.h │ │ │ ├── MaterialSelector.cpp │ │ │ ├── MaterialSelector.h │ │ │ ├── MaterialThumbnailBrowser.cpp │ │ │ ├── MaterialThumbnailBrowser.h │ │ │ ├── MaterialTreeView.cpp │ │ │ ├── MaterialTreeView.h │ │ │ └── editor/ │ │ │ ├── Binding.h │ │ │ ├── CheckBoxBinding.h │ │ │ ├── ExpressionBinding.h │ │ │ ├── MapExpressionEntry.h │ │ │ ├── MaterialEditor.cpp │ │ │ ├── MaterialEditor.h │ │ │ ├── MaterialEditorModule.cpp │ │ │ ├── MaterialPreview.cpp │ │ │ ├── MaterialPreview.h │ │ │ ├── RadioButtonBinding.h │ │ │ ├── SpinCtrlBinding.h │ │ │ ├── TestModelSkin.h │ │ │ └── TexturePreview.h │ │ ├── mediabrowser/ │ │ │ ├── FocusMaterialRequest.h │ │ │ ├── MediaBrowser.cpp │ │ │ ├── MediaBrowser.h │ │ │ ├── MediaBrowserModule.cpp │ │ │ ├── MediaBrowserTreeView.cpp │ │ │ ├── MediaBrowserTreeView.h │ │ │ └── TextureDirectoryLoader.h │ │ ├── menu/ │ │ │ ├── MenuBar.cpp │ │ │ ├── MenuBar.h │ │ │ ├── MenuElement.cpp │ │ │ ├── MenuElement.h │ │ │ ├── MenuFolder.cpp │ │ │ ├── MenuFolder.h │ │ │ ├── MenuItem.cpp │ │ │ ├── MenuItem.h │ │ │ ├── MenuManager.cpp │ │ │ ├── MenuManager.h │ │ │ ├── MenuRootElement.h │ │ │ ├── MenuSeparator.cpp │ │ │ └── MenuSeparator.h │ │ ├── merge/ │ │ │ ├── MapMergeControl.h │ │ │ ├── MapMergePanel.cpp │ │ │ └── MapMergePanel.h │ │ ├── modelexport/ │ │ │ ├── ConvertModelDialog.cpp │ │ │ ├── ConvertModelDialog.h │ │ │ ├── ExportAsModelDialog.cpp │ │ │ ├── ExportAsModelDialog.h │ │ │ ├── ExportCollisionModelDialog.cpp │ │ │ └── ExportCollisionModelDialog.h │ │ ├── modelselector/ │ │ │ ├── MaterialsList.cpp │ │ │ ├── MaterialsList.h │ │ │ ├── ModelDataInserter.h │ │ │ ├── ModelPopulator.h │ │ │ ├── ModelSelector.cpp │ │ │ ├── ModelSelector.h │ │ │ ├── ModelTreeView.cpp │ │ │ └── ModelTreeView.h │ │ ├── mousetool/ │ │ │ ├── BindToolDialog.cpp │ │ │ ├── BindToolDialog.h │ │ │ ├── RegistrationHelper.h │ │ │ ├── ToolMappingDialog.cpp │ │ │ └── ToolMappingDialog.h │ │ ├── mru/ │ │ │ └── MRUMenu.h │ │ ├── ortho/ │ │ │ ├── OrthoContextMenu.cpp │ │ │ └── OrthoContextMenu.h │ │ ├── overlay/ │ │ │ ├── OrthoBackgroundControl.h │ │ │ ├── OrthoBackgroundPanel.cpp │ │ │ ├── OrthoBackgroundPanel.h │ │ │ ├── Overlay.cpp │ │ │ ├── Overlay.h │ │ │ └── OverlayRegistryKeys.h │ │ ├── particles/ │ │ │ ├── ParticleChooserDialog.cpp │ │ │ ├── ParticleChooserDialog.h │ │ │ ├── ParticleEditor.cpp │ │ │ ├── ParticleEditor.h │ │ │ ├── ParticleSelector.cpp │ │ │ ├── ParticleSelector.h │ │ │ └── ThreadedParticlesLoader.h │ │ ├── patch/ │ │ │ ├── BulgePatchDialog.cpp │ │ │ ├── BulgePatchDialog.h │ │ │ ├── CapDialog.cpp │ │ │ ├── CapDialog.h │ │ │ ├── PatchCreateDialog.cpp │ │ │ ├── PatchCreateDialog.h │ │ │ ├── PatchInspector.cpp │ │ │ ├── PatchInspector.h │ │ │ ├── PatchInspectorControl.h │ │ │ ├── PatchPrefabDialog.cpp │ │ │ ├── PatchPrefabDialog.h │ │ │ ├── PatchThickenDialog.cpp │ │ │ └── PatchThickenDialog.h │ │ ├── prefabselector/ │ │ │ ├── PrefabSelector.cpp │ │ │ └── PrefabSelector.h │ │ ├── prefdialog/ │ │ │ ├── GameSetupDialog.cpp │ │ │ ├── GameSetupDialog.h │ │ │ ├── GameSetupPage.cpp │ │ │ ├── GameSetupPage.h │ │ │ ├── GameSetupPageIdTech.cpp │ │ │ ├── GameSetupPageIdTech.h │ │ │ ├── GameSetupPageTdm.cpp │ │ │ ├── GameSetupPageTdm.h │ │ │ ├── PrefDialog.cpp │ │ │ ├── PrefDialog.h │ │ │ ├── PrefPage.cpp │ │ │ ├── PrefPage.h │ │ │ ├── PreferenceItem.cpp │ │ │ └── PreferenceItem.h │ │ ├── scatter/ │ │ │ ├── ScatterDialog.cpp │ │ │ └── ScatterDialog.h │ │ ├── script/ │ │ │ ├── ScriptMenu.cpp │ │ │ ├── ScriptMenu.h │ │ │ ├── ScriptPanel.h │ │ │ ├── ScriptWindow.cpp │ │ │ └── ScriptWindow.h │ │ ├── selectiongroup/ │ │ │ ├── SelectionGroupControl.h │ │ │ ├── SelectionGroupPanel.cpp │ │ │ └── SelectionGroupPanel.h │ │ ├── selectionset/ │ │ │ ├── SelectionSetToolmenu.cpp │ │ │ └── SelectionSetToolmenu.h │ │ ├── skin/ │ │ │ ├── SkinEditor.cpp │ │ │ ├── SkinEditor.h │ │ │ ├── SkinEditorTreeView.cpp │ │ │ └── SkinEditorTreeView.h │ │ ├── splash/ │ │ │ ├── Splash.cpp │ │ │ └── Splash.h │ │ ├── statusbar/ │ │ │ ├── CommandStatus.cpp │ │ │ ├── CommandStatus.h │ │ │ ├── EditingStopwatchStatus.cpp │ │ │ ├── EditingStopwatchStatus.h │ │ │ ├── MapStatistics.cpp │ │ │ ├── MapStatistics.h │ │ │ ├── ShaderClipboardStatus.h │ │ │ ├── StatusBarManager.cpp │ │ │ └── StatusBarManager.h │ │ ├── surfaceinspector/ │ │ │ ├── SurfaceInspector.cpp │ │ │ ├── SurfaceInspector.h │ │ │ └── SurfaceInspectorControl.h │ │ ├── terrain/ │ │ │ ├── TerrainGeneratorDialog.cpp │ │ │ └── TerrainGeneratorDialog.h │ │ ├── texturebrowser/ │ │ │ ├── MapTextureBrowser.cpp │ │ │ ├── MapTextureBrowser.h │ │ │ ├── TextureBrowserManager.cpp │ │ │ ├── TextureBrowserManager.h │ │ │ ├── TextureBrowserPanel.cpp │ │ │ ├── TextureBrowserPanel.h │ │ │ ├── TextureDirectoryBrowser.h │ │ │ ├── TextureThumbnailBrowser.cpp │ │ │ └── TextureThumbnailBrowser.h │ │ ├── toolbar/ │ │ │ ├── ToolbarManager.cpp │ │ │ └── ToolbarManager.h │ │ └── transform/ │ │ ├── TransformPanel.cpp │ │ ├── TransformPanel.h │ │ └── TransformPanelControl.h │ └── xyview/ │ ├── GlobalXYWnd.cpp │ ├── GlobalXYWnd.h │ ├── OrthoView.cpp │ ├── OrthoView.h │ ├── XYRenderer.h │ └── tools/ │ ├── BrushCreatorTool.cpp │ ├── BrushCreatorTool.h │ ├── CameraAngleTool.h │ ├── CameraMoveTool.h │ ├── ClipperTool.cpp │ ├── ClipperTool.h │ ├── MeasurementTool.cpp │ ├── MeasurementTool.h │ ├── MoveViewTool.h │ ├── PolygonTool.cpp │ ├── PolygonTool.h │ ├── XYMouseToolEvent.h │ └── ZoomTool.h ├── radiantcore/ │ ├── CMakeLists.txt │ ├── Radiant.cpp │ ├── Radiant.h │ ├── brush/ │ │ ├── Brush.cpp │ │ ├── Brush.h │ │ ├── BrushClipPlane.h │ │ ├── BrushModule.cpp │ │ ├── BrushModule.h │ │ ├── BrushNode.cpp │ │ ├── BrushNode.h │ │ ├── BrushSettings.h │ │ ├── BrushVisit.h │ │ ├── EdgeInstance.h │ │ ├── Face.cpp │ │ ├── Face.h │ │ ├── FaceInstance.cpp │ │ ├── FaceInstance.h │ │ ├── FacePlane.cpp │ │ ├── FacePlane.h │ │ ├── FixedWinding.cpp │ │ ├── FixedWinding.h │ │ ├── PlanePoints.h │ │ ├── RenderableBrushVertices.cpp │ │ ├── RenderableBrushVertices.h │ │ ├── RenderableWinding.h │ │ ├── SelectableComponents.h │ │ ├── TextureMatrix.cpp │ │ ├── TextureMatrix.h │ │ ├── TextureProjection.cpp │ │ ├── TextureProjection.h │ │ ├── VertexInstance.h │ │ ├── VertexSelection.h │ │ ├── Winding.cpp │ │ ├── Winding.h │ │ ├── csg/ │ │ │ ├── CSG.cpp │ │ │ └── CSG.h │ │ └── export/ │ │ ├── CollisionModel.cpp │ │ ├── CollisionModel.h │ │ └── Geometry.h │ ├── camera/ │ │ ├── Camera.cpp │ │ ├── Camera.h │ │ ├── CameraManager.cpp │ │ └── CameraManager.h │ ├── clipper/ │ │ ├── BrushByPlaneClipper.cpp │ │ ├── BrushByPlaneClipper.h │ │ ├── ClipPoint.cpp │ │ ├── ClipPoint.h │ │ ├── Clipper.cpp │ │ ├── Clipper.h │ │ ├── SplitAlgorithm.cpp │ │ └── SplitAlgorithm.h │ ├── commandsystem/ │ │ ├── Command.h │ │ ├── CommandSystem.cpp │ │ ├── CommandSystem.h │ │ ├── CommandTokeniser.h │ │ ├── Executable.h │ │ └── Statement.h │ ├── decl/ │ │ ├── DeclarationFile.h │ │ ├── DeclarationFolderParser.cpp │ │ ├── DeclarationFolderParser.h │ │ ├── DeclarationManager.cpp │ │ ├── DeclarationManager.h │ │ ├── FavouriteSet.h │ │ ├── FavouritesManager.cpp │ │ └── FavouritesManager.h │ ├── eclass/ │ │ ├── Doom3ModelDef.h │ │ ├── EClassColourManager.cpp │ │ ├── EClassColourManager.h │ │ ├── EClassManager.cpp │ │ └── EClassManager.h │ ├── entity/ │ │ ├── AngleKey.cpp │ │ ├── AngleKey.h │ │ ├── EntityModule.cpp │ │ ├── EntityModule.h │ │ ├── RenderableArrow.cpp │ │ ├── RenderableArrow.h │ │ ├── RenderableEntityBox.cpp │ │ ├── RenderableEntityBox.h │ │ ├── RotationKey.cpp │ │ ├── RotationKey.h │ │ ├── RotationMatrix.cpp │ │ ├── RotationMatrix.h │ │ ├── VertexInstance.h │ │ ├── algorithm/ │ │ │ └── Speaker.h │ │ ├── curve/ │ │ │ ├── Curve.cpp │ │ │ ├── Curve.h │ │ │ ├── CurveCatmullRom.cpp │ │ │ ├── CurveCatmullRom.h │ │ │ ├── CurveControlPointFunctors.h │ │ │ ├── CurveEditInstance.cpp │ │ │ ├── CurveEditInstance.h │ │ │ ├── CurveNURBS.cpp │ │ │ ├── CurveNURBS.h │ │ │ ├── RenderableCurve.h │ │ │ └── RenderableCurveVertices.h │ │ ├── doom3group/ │ │ │ ├── RenderableVertex.h │ │ │ ├── StaticGeometryNode.cpp │ │ │ └── StaticGeometryNode.h │ │ ├── eclassmodel/ │ │ │ ├── EclassModelNode.cpp │ │ │ └── EclassModelNode.h │ │ ├── generic/ │ │ │ ├── GenericEntityNode.cpp │ │ │ └── GenericEntityNode.h │ │ ├── light/ │ │ │ ├── Doom3LightRadius.h │ │ │ ├── LightNode.cpp │ │ │ ├── LightNode.h │ │ │ ├── LightShader.h │ │ │ ├── LightVertexInstanceSet.h │ │ │ ├── Renderables.cpp │ │ │ └── Renderables.h │ │ └── speaker/ │ │ ├── SpeakerNode.cpp │ │ ├── SpeakerNode.h │ │ ├── SpeakerRenderables.cpp │ │ └── SpeakerRenderables.h │ ├── filetypes/ │ │ ├── FileTypeRegistry.cpp │ │ └── FileTypeRegistry.h │ ├── filters/ │ │ ├── BasicFilterSystem.cpp │ │ ├── BasicFilterSystem.h │ │ ├── InstanceUpdateWalker.h │ │ ├── SetObjectSelectionByFilterWalker.h │ │ ├── XmlFilterEventAdapter.cpp │ │ └── XmlFilterEventAdapter.h │ ├── fonts/ │ │ ├── FontInfo.h │ │ ├── FontLoader.cpp │ │ ├── FontLoader.h │ │ ├── FontManager.cpp │ │ ├── FontManager.h │ │ ├── GlyphInfo.cpp │ │ ├── GlyphInfo.h │ │ ├── GlyphSet.cpp │ │ └── GlyphSet.h │ ├── fx/ │ │ ├── FxAction.cpp │ │ ├── FxAction.h │ │ ├── FxDeclaration.cpp │ │ ├── FxDeclaration.h │ │ ├── FxManager.cpp │ │ └── FxManager.h │ ├── grid/ │ │ ├── GridItem.h │ │ ├── GridManager.cpp │ │ └── GridManager.h │ ├── imagefile/ │ │ ├── BMPLoader.cpp │ │ ├── BMPLoader.h │ │ ├── ImageLoader.cpp │ │ ├── ImageLoader.h │ │ ├── ImageTypeLoader.h │ │ ├── JPEGLoader.cpp │ │ ├── JPEGLoader.h │ │ ├── PNGLoader.cpp │ │ ├── PNGLoader.h │ │ ├── TGALoader.cpp │ │ ├── TGALoader.h │ │ ├── dds.cpp │ │ ├── dds.h │ │ ├── ddslib.cpp │ │ └── ddslib.h │ ├── layers/ │ │ ├── AddToLayerWalker.h │ │ ├── LayerInfoFileModule.cpp │ │ ├── LayerInfoFileModule.h │ │ ├── LayerManager.cpp │ │ ├── LayerManager.h │ │ ├── LayerModule.cpp │ │ ├── MoveToLayerWalker.h │ │ ├── RemoveFromLayerWalker.h │ │ └── SetLayerSelectedWalker.h │ ├── log/ │ │ ├── COutRedirector.cpp │ │ ├── COutRedirector.h │ │ ├── LogFile.cpp │ │ ├── LogFile.h │ │ ├── LogStream.cpp │ │ ├── LogStream.h │ │ ├── LogStreamBuf.cpp │ │ ├── LogStreamBuf.h │ │ ├── LogWriter.cpp │ │ ├── LogWriter.h │ │ ├── SegFaultHandler.cpp │ │ ├── SegFaultHandler.h │ │ ├── StringLogDevice.cpp │ │ └── StringLogDevice.h │ ├── map/ │ │ ├── ArchivedMapResource.cpp │ │ ├── ArchivedMapResource.h │ │ ├── CounterManager.cpp │ │ ├── CounterManager.h │ │ ├── EditingStopwatch.cpp │ │ ├── EditingStopwatch.h │ │ ├── EditingStopwatchInfoFileModule.cpp │ │ ├── EditingStopwatchInfoFileModule.h │ │ ├── Map.cpp │ │ ├── Map.h │ │ ├── MapFileManager.cpp │ │ ├── MapFileManager.h │ │ ├── MapModules.cpp │ │ ├── MapPosition.cpp │ │ ├── MapPosition.h │ │ ├── MapPositionManager.cpp │ │ ├── MapPositionManager.h │ │ ├── MapPropertyInfoFileModule.cpp │ │ ├── MapPropertyInfoFileModule.h │ │ ├── MapResource.cpp │ │ ├── MapResource.h │ │ ├── MapResourceLoader.cpp │ │ ├── MapResourceLoader.h │ │ ├── MapResourceManager.cpp │ │ ├── MapResourceManager.h │ │ ├── NodeCounter.h │ │ ├── PointFile.cpp │ │ ├── PointFile.h │ │ ├── RegionManager.cpp │ │ ├── RegionManager.h │ │ ├── RegionWalkers.h │ │ ├── RenderablePointFile.h │ │ ├── RootNode.cpp │ │ ├── RootNode.h │ │ ├── VcsMapResource.cpp │ │ ├── VcsMapResource.h │ │ ├── aas/ │ │ │ ├── AasFileManager.cpp │ │ │ ├── AasFileManager.h │ │ │ ├── Doom3AasFile.cpp │ │ │ ├── Doom3AasFile.h │ │ │ ├── Doom3AasFileLoader.cpp │ │ │ ├── Doom3AasFileLoader.h │ │ │ ├── Doom3AasFileSettings.cpp │ │ │ ├── Doom3AasFileSettings.h │ │ │ └── Util.h │ │ ├── algorithm/ │ │ │ ├── Export.cpp │ │ │ ├── Export.h │ │ │ ├── Import.cpp │ │ │ ├── Import.h │ │ │ ├── MapExporter.cpp │ │ │ ├── MapExporter.h │ │ │ ├── MapImporter.cpp │ │ │ ├── MapImporter.h │ │ │ ├── Models.cpp │ │ │ └── Models.h │ │ ├── autosaver/ │ │ │ ├── AutoSaver.cpp │ │ │ └── AutoSaver.h │ │ ├── format/ │ │ │ ├── Doom3MapFormat.cpp │ │ │ ├── Doom3MapFormat.h │ │ │ ├── Doom3MapReader.cpp │ │ │ ├── Doom3MapReader.h │ │ │ ├── Doom3MapWriter.cpp │ │ │ ├── Doom3MapWriter.h │ │ │ ├── Doom3PrefabFormat.cpp │ │ │ ├── Doom3PrefabFormat.h │ │ │ ├── MapFormatManager.cpp │ │ │ ├── MapFormatManager.h │ │ │ ├── Quake3MapFormat.cpp │ │ │ ├── Quake3MapFormat.h │ │ │ ├── Quake3MapReader.cpp │ │ │ ├── Quake3MapReader.h │ │ │ ├── Quake3MapWriter.h │ │ │ ├── Quake3Utils.h │ │ │ ├── Quake4MapFormat.cpp │ │ │ ├── Quake4MapFormat.h │ │ │ ├── Quake4MapReader.cpp │ │ │ ├── Quake4MapReader.h │ │ │ ├── Quake4MapWriter.h │ │ │ ├── portable/ │ │ │ │ ├── Constants.h │ │ │ │ ├── PortableMapFormat.cpp │ │ │ │ ├── PortableMapFormat.h │ │ │ │ ├── PortableMapReader.cpp │ │ │ │ ├── PortableMapReader.h │ │ │ │ ├── PortableMapWriter.cpp │ │ │ │ └── PortableMapWriter.h │ │ │ ├── primitiveparsers/ │ │ │ │ ├── BrushDef.cpp │ │ │ │ ├── BrushDef.h │ │ │ │ ├── BrushDef3.cpp │ │ │ │ ├── BrushDef3.h │ │ │ │ ├── Patch.cpp │ │ │ │ ├── Patch.h │ │ │ │ ├── PatchDef2.cpp │ │ │ │ ├── PatchDef2.h │ │ │ │ ├── PatchDef3.cpp │ │ │ │ └── PatchDef3.h │ │ │ └── primitivewriters/ │ │ │ ├── BrushDef3Exporter.h │ │ │ ├── BrushDefExporter.h │ │ │ ├── ExportUtil.h │ │ │ ├── LegacyBrushDefExporter.h │ │ │ └── PatchDefExporter.h │ │ ├── infofile/ │ │ │ ├── InfoFile.cpp │ │ │ ├── InfoFile.h │ │ │ ├── InfoFileExporter.cpp │ │ │ ├── InfoFileExporter.h │ │ │ ├── InfoFileManager.cpp │ │ │ └── InfoFileManager.h │ │ ├── mru/ │ │ │ ├── MRU.cpp │ │ │ ├── MRU.h │ │ │ └── MRUList.h │ │ └── namespace/ │ │ ├── ComplexName.cpp │ │ ├── ComplexName.h │ │ ├── Namespace.cpp │ │ ├── Namespace.h │ │ ├── NamespaceFactory.cpp │ │ ├── NamespaceFactory.h │ │ └── UniqueNameSet.h │ ├── messagebus/ │ │ └── MessageBus.h │ ├── model/ │ │ ├── IndexedBoxSurface.h │ │ ├── ModelCache.cpp │ │ ├── ModelCache.h │ │ ├── ModelFormatManager.cpp │ │ ├── ModelFormatManager.h │ │ ├── ModelNodeBase.cpp │ │ ├── ModelNodeBase.h │ │ ├── NullModel.cpp │ │ ├── NullModel.h │ │ ├── NullModelBoxSurface.h │ │ ├── NullModelLoader.h │ │ ├── NullModelNode.cpp │ │ ├── NullModelNode.h │ │ ├── RenderableModelSurface.h │ │ ├── StaticModel.cpp │ │ ├── StaticModel.h │ │ ├── StaticModelNode.cpp │ │ ├── StaticModelNode.h │ │ ├── StaticModelSurface.cpp │ │ ├── StaticModelSurface.h │ │ ├── export/ │ │ │ ├── AseExporter.cpp │ │ │ ├── AseExporter.h │ │ │ ├── Lwo2Chunk.cpp │ │ │ ├── Lwo2Chunk.h │ │ │ ├── Lwo2Exporter.cpp │ │ │ ├── Lwo2Exporter.h │ │ │ ├── ModelExporter.cpp │ │ │ ├── ModelExporter.h │ │ │ ├── ModelExporterBase.h │ │ │ ├── ModelScalePreserver.cpp │ │ │ ├── ModelScalePreserver.h │ │ │ ├── PatchSurface.cpp │ │ │ ├── PatchSurface.h │ │ │ ├── ScaledModelExporter.cpp │ │ │ ├── ScaledModelExporter.h │ │ │ ├── WavefrontExporter.cpp │ │ │ └── WavefrontExporter.h │ │ ├── import/ │ │ │ ├── AseModel.cpp │ │ │ ├── AseModel.h │ │ │ ├── AseModelLoader.cpp │ │ │ ├── AseModelLoader.h │ │ │ ├── FbxModelLoader.cpp │ │ │ ├── FbxModelLoader.h │ │ │ ├── FbxSurface.h │ │ │ ├── ModelImporterBase.cpp │ │ │ ├── ModelImporterBase.h │ │ │ └── openfbx/ │ │ │ ├── LICENSE │ │ │ ├── ofbx.cpp │ │ │ └── ofbx.h │ │ ├── md5/ │ │ │ ├── MD5Anim.cpp │ │ │ ├── MD5Anim.h │ │ │ ├── MD5AnimationCache.cpp │ │ │ ├── MD5AnimationCache.h │ │ │ ├── MD5DataStructures.h │ │ │ ├── MD5Model.cpp │ │ │ ├── MD5Model.h │ │ │ ├── MD5ModelLoader.cpp │ │ │ ├── MD5ModelLoader.h │ │ │ ├── MD5ModelNode.cpp │ │ │ ├── MD5ModelNode.h │ │ │ ├── MD5Module.cpp │ │ │ ├── MD5Skeleton.cpp │ │ │ ├── MD5Skeleton.h │ │ │ ├── MD5Surface.cpp │ │ │ ├── MD5Surface.h │ │ │ └── RenderableMD5Skeleton.h │ │ └── picomodel/ │ │ ├── PicoModelLoader.cpp │ │ ├── PicoModelLoader.h │ │ ├── PicoModelModule.cpp │ │ ├── PicoModelModule.h │ │ └── lib/ │ │ ├── lwo/ │ │ │ ├── clip.c │ │ │ ├── envelope.c │ │ │ ├── list.c │ │ │ ├── lwio.c │ │ │ ├── lwo2.c │ │ │ ├── lwo2.h │ │ │ ├── lwob.c │ │ │ ├── pntspols.c │ │ │ ├── surface.c │ │ │ ├── vecmath.c │ │ │ └── vmap.c │ │ ├── picointernal.c │ │ ├── picointernal.h │ │ ├── picomodel.c │ │ ├── picomodel.h │ │ ├── picomodules.c │ │ ├── pm_3ds.c │ │ ├── pm_fm.c │ │ ├── pm_fm.h │ │ ├── pm_fm.h.orig │ │ ├── pm_iqm.c │ │ ├── pm_lwo.c │ │ ├── pm_md2.c │ │ ├── pm_md3.c │ │ ├── pm_mdc.c │ │ ├── pm_ms3d.c │ │ ├── pm_obj.c │ │ └── pm_terrain.c │ ├── modulesystem/ │ │ ├── ModuleLoader.cpp │ │ ├── ModuleLoader.h │ │ ├── ModuleRegistry.cpp │ │ └── ModuleRegistry.h │ ├── particles/ │ │ ├── ParticleDef.cpp │ │ ├── ParticleDef.h │ │ ├── ParticleNode.cpp │ │ ├── ParticleNode.h │ │ ├── ParticleParameter.cpp │ │ ├── ParticleParameter.h │ │ ├── ParticleQuad.h │ │ ├── ParticleRenderInfo.h │ │ ├── ParticlesManager.cpp │ │ ├── ParticlesManager.h │ │ ├── RenderableParticle.cpp │ │ ├── RenderableParticle.h │ │ ├── RenderableParticleBunch.cpp │ │ ├── RenderableParticleBunch.h │ │ ├── RenderableParticleStage.cpp │ │ ├── RenderableParticleStage.h │ │ ├── StageDef.cpp │ │ └── StageDef.h │ ├── patch/ │ │ ├── Patch.cpp │ │ ├── Patch.h │ │ ├── PatchConstants.h │ │ ├── PatchControl.h │ │ ├── PatchControlInstance.h │ │ ├── PatchModule.cpp │ │ ├── PatchModule.h │ │ ├── PatchNode.cpp │ │ ├── PatchNode.h │ │ ├── PatchRenderables.cpp │ │ ├── PatchRenderables.h │ │ ├── PatchSavedState.h │ │ ├── PatchSettings.h │ │ ├── PatchTesselation.cpp │ │ ├── PatchTesselation.h │ │ └── algorithm/ │ │ ├── General.cpp │ │ ├── General.h │ │ ├── Prefab.cpp │ │ └── Prefab.h │ ├── precompiled.cpp │ ├── precompiled.h │ ├── rendersystem/ │ │ ├── GLFont.cpp │ │ ├── GLFont.h │ │ ├── OpenGLModule.cpp │ │ ├── OpenGLModule.h │ │ ├── OpenGLRenderSystem.cpp │ │ ├── OpenGLRenderSystem.h │ │ ├── RenderSystemFactory.cpp │ │ ├── RenderSystemFactory.h │ │ ├── SharedOpenGLContextModule.cpp │ │ ├── SharedOpenGLContextModule.h │ │ ├── backend/ │ │ │ ├── BlendLight.cpp │ │ │ ├── BlendLight.h │ │ │ ├── BufferObjectProvider.h │ │ │ ├── BuiltInShader.cpp │ │ │ ├── BuiltInShader.h │ │ │ ├── ColourShader.cpp │ │ │ ├── ColourShader.h │ │ │ ├── DepthFillPass.cpp │ │ │ ├── DepthFillPass.h │ │ │ ├── FenceSyncProvider.h │ │ │ ├── FrameBuffer.h │ │ │ ├── FullBrightRenderer.cpp │ │ │ ├── FullBrightRenderer.h │ │ │ ├── GLProgramFactory.cpp │ │ │ ├── GLProgramFactory.h │ │ │ ├── GeometryRenderer.h │ │ │ ├── InteractionPass.cpp │ │ │ ├── InteractionPass.h │ │ │ ├── LightingModeRenderResult.h │ │ │ ├── LightingModeRenderer.cpp │ │ │ ├── LightingModeRenderer.h │ │ │ ├── ObjectRenderer.cpp │ │ │ ├── ObjectRenderer.h │ │ │ ├── OpenGLShader.cpp │ │ │ ├── OpenGLShader.h │ │ │ ├── OpenGLShaderPass.cpp │ │ │ ├── OpenGLShaderPass.h │ │ │ ├── OpenGLState.h │ │ │ ├── OpenGLStateLess.h │ │ │ ├── OpenGLStateManager.h │ │ │ ├── RegularLight.cpp │ │ │ ├── RegularLight.h │ │ │ ├── SceneRenderer.cpp │ │ │ ├── SceneRenderer.h │ │ │ ├── SurfaceRenderer.h │ │ │ ├── TextRenderer.h │ │ │ └── glprogram/ │ │ │ ├── BlendLightProgram.cpp │ │ │ ├── BlendLightProgram.h │ │ │ ├── CubeMapProgram.cpp │ │ │ ├── CubeMapProgram.h │ │ │ ├── DepthFillAlphaProgram.cpp │ │ │ ├── DepthFillAlphaProgram.h │ │ │ ├── GLSLProgramBase.cpp │ │ │ ├── GLSLProgramBase.h │ │ │ ├── GenericVFPProgram.cpp │ │ │ ├── GenericVFPProgram.h │ │ │ ├── InteractionProgram.cpp │ │ │ ├── InteractionProgram.h │ │ │ ├── RegularStageProgram.cpp │ │ │ ├── RegularStageProgram.h │ │ │ ├── ShadowMapProgram.cpp │ │ │ └── ShadowMapProgram.h │ │ └── debug/ │ │ ├── SpacePartitionRenderer.cpp │ │ └── SpacePartitionRenderer.h │ ├── scenegraph/ │ │ ├── Octree.cpp │ │ ├── Octree.h │ │ ├── OctreeNode.h │ │ ├── SceneGraph.cpp │ │ ├── SceneGraph.h │ │ ├── SceneGraphFactory.cpp │ │ └── SceneGraphFactory.h │ ├── selection/ │ │ ├── BasicSelectable.h │ │ ├── BestSelector.h │ │ ├── ManipulationPivot.cpp │ │ ├── ManipulationPivot.h │ │ ├── RadiantSelectionSystem.cpp │ │ ├── RadiantSelectionSystem.h │ │ ├── SceneManipulationPivot.cpp │ │ ├── SceneManipulationPivot.h │ │ ├── SceneSelectionTesters.cpp │ │ ├── SceneSelectionTesters.h │ │ ├── SceneWalkers.h │ │ ├── SelectedNodeList.cpp │ │ ├── SelectedNodeList.h │ │ ├── SelectionTestWalkers.cpp │ │ ├── SelectionTestWalkers.h │ │ ├── TransformationVisitors.cpp │ │ ├── TransformationVisitors.h │ │ ├── algorithm/ │ │ │ ├── Curves.cpp │ │ │ ├── Curves.h │ │ │ ├── Entity.cpp │ │ │ ├── Entity.h │ │ │ ├── General.cpp │ │ │ ├── General.h │ │ │ ├── Group.cpp │ │ │ ├── Group.h │ │ │ ├── GroupCycle.cpp │ │ │ ├── GroupCycle.h │ │ │ ├── Patch.cpp │ │ │ ├── Patch.h │ │ │ ├── Planes.cpp │ │ │ ├── Planes.h │ │ │ ├── Primitives.cpp │ │ │ ├── Primitives.h │ │ │ ├── SelectionPolicies.h │ │ │ ├── Shader.cpp │ │ │ ├── Shader.h │ │ │ ├── Texturing.cpp │ │ │ ├── Texturing.h │ │ │ ├── Transformation.cpp │ │ │ └── Transformation.h │ │ ├── clipboard/ │ │ │ ├── Clipboard.cpp │ │ │ └── Clipboard.h │ │ ├── group/ │ │ │ ├── SelectionGroup.h │ │ │ ├── SelectionGroupInfoFileModule.cpp │ │ │ ├── SelectionGroupInfoFileModule.h │ │ │ ├── SelectionGroupManager.cpp │ │ │ ├── SelectionGroupManager.h │ │ │ └── SelectionGroupModule.cpp │ │ ├── manipulators/ │ │ │ ├── ClipManipulator.h │ │ │ ├── DragManipulator.cpp │ │ │ ├── DragManipulator.h │ │ │ ├── ManipulatorBase.cpp │ │ │ ├── ManipulatorBase.h │ │ │ ├── ManipulatorComponents.cpp │ │ │ ├── ManipulatorComponents.h │ │ │ ├── ModelScaleManipulator.cpp │ │ │ ├── ModelScaleManipulator.h │ │ │ ├── Renderables.h │ │ │ ├── RotateManipulator.cpp │ │ │ ├── RotateManipulator.h │ │ │ ├── TranslateManipulator.cpp │ │ │ └── TranslateManipulator.h │ │ ├── selectionset/ │ │ │ ├── SelectionSet.cpp │ │ │ ├── SelectionSet.h │ │ │ ├── SelectionSetInfoFileModule.cpp │ │ │ ├── SelectionSetInfoFileModule.h │ │ │ ├── SelectionSetManager.cpp │ │ │ ├── SelectionSetManager.h │ │ │ └── SelectionSetModule.cpp │ │ ├── shaderclipboard/ │ │ │ ├── ClosestTexturableFinder.cpp │ │ │ ├── ClosestTexturableFinder.h │ │ │ ├── ShaderClipboard.cpp │ │ │ ├── ShaderClipboard.h │ │ │ ├── Texturable.cpp │ │ │ └── Texturable.h │ │ └── textool/ │ │ ├── ColourSchemeManager.cpp │ │ ├── FaceNode.cpp │ │ ├── FaceNode.h │ │ ├── Node.cpp │ │ ├── Node.h │ │ ├── PatchNode.cpp │ │ ├── PatchNode.h │ │ ├── SelectableVertex.h │ │ ├── TextureToolDragManipulator.cpp │ │ ├── TextureToolDragManipulator.h │ │ ├── TextureToolManipulationPivot.cpp │ │ ├── TextureToolManipulationPivot.h │ │ ├── TextureToolRotateManipulator.cpp │ │ ├── TextureToolRotateManipulator.h │ │ ├── TextureToolSceneGraph.cpp │ │ ├── TextureToolSceneGraph.h │ │ ├── TextureToolSelectionSystem.cpp │ │ └── TextureToolSelectionSystem.h │ ├── settings/ │ │ ├── ColourScheme.cpp │ │ ├── ColourScheme.h │ │ ├── ColourSchemeManager.cpp │ │ ├── ColourSchemeManager.h │ │ ├── Game.cpp │ │ ├── Game.h │ │ ├── GameManager.cpp │ │ ├── GameManager.h │ │ ├── LanguageManager.cpp │ │ ├── LanguageManager.h │ │ ├── PreferenceItemBase.h │ │ ├── PreferenceItems.h │ │ ├── PreferencePage.cpp │ │ ├── PreferencePage.h │ │ ├── PreferenceSystem.cpp │ │ └── PreferenceSystem.h │ ├── shaders/ │ │ ├── CShader.cpp │ │ ├── CShader.h │ │ ├── CameraCubeMapDecl.cpp │ │ ├── CameraCubeMapDecl.h │ │ ├── Doom3ShaderLayer.cpp │ │ ├── Doom3ShaderLayer.h │ │ ├── ExpressionSlots.cpp │ │ ├── ExpressionSlots.h │ │ ├── MapExpression.cpp │ │ ├── MapExpression.h │ │ ├── MaterialManager.cpp │ │ ├── MaterialManager.h │ │ ├── MaterialSourceGenerator.cpp │ │ ├── MaterialSourceGenerator.h │ │ ├── ShaderLibrary.cpp │ │ ├── ShaderLibrary.h │ │ ├── ShaderTemplate.cpp │ │ ├── ShaderTemplate.h │ │ ├── SoundMapExpression.h │ │ ├── TableDefinition.cpp │ │ ├── TableDefinition.h │ │ ├── TextureMatrix.cpp │ │ ├── TextureMatrix.h │ │ ├── VideoMapExpression.h │ │ └── textures/ │ │ ├── CubeMapTexture.h │ │ ├── GLTextureManager.cpp │ │ └── GLTextureManager.h │ ├── skins/ │ │ ├── Doom3ModelSkin.cpp │ │ ├── Doom3ModelSkin.h │ │ ├── Doom3SkinCache.cpp │ │ └── Doom3SkinCache.h │ ├── undo/ │ │ ├── Operation.h │ │ ├── Stack.h │ │ ├── StackFiller.h │ │ ├── UndoSystem.cpp │ │ ├── UndoSystem.h │ │ └── UndoSystemFactory.cpp │ ├── versioncontrol/ │ │ ├── VersionControlManager.cpp │ │ └── VersionControlManager.h │ ├── vfs/ │ │ ├── AssetsList.h │ │ ├── DeflatedArchiveFile.h │ │ ├── DeflatedArchiveTextFile.h │ │ ├── DeflatedInputStream.cpp │ │ ├── DeflatedInputStream.h │ │ ├── DirectoryArchive.cpp │ │ ├── DirectoryArchive.h │ │ ├── DirectoryArchiveTextFile.h │ │ ├── Doom3FileSystem.cpp │ │ ├── Doom3FileSystem.h │ │ ├── FileVisitor.h │ │ ├── GenericFileSystem.h │ │ ├── SortedFilenames.h │ │ ├── StoredArchiveFile.h │ │ ├── StoredArchiveTextFile.h │ │ ├── UnixPath.h │ │ ├── ZipArchive.cpp │ │ ├── ZipArchive.h │ │ └── ZipStreamUtils.h │ └── xmlregistry/ │ ├── RegistryTree.cpp │ ├── RegistryTree.h │ ├── XMLRegistry.cpp │ └── XMLRegistry.h ├── test/ │ ├── Basic.cpp │ ├── Brush.cpp │ ├── CMakeLists.txt │ ├── CSG.cpp │ ├── Camera.cpp │ ├── Clipboard.cpp │ ├── CodeTokeniser.cpp │ ├── ColourSchemes.cpp │ ├── CommandSystem.cpp │ ├── ContinuousBuffer.cpp │ ├── Curves.cpp │ ├── DeclManager.cpp │ ├── DefBlockSyntaxParser.cpp │ ├── DefTokenisers.cpp │ ├── Entity.cpp │ ├── EntityClass.cpp │ ├── EntityInspector.cpp │ ├── FakeClipboardModule.h │ ├── Favourites.cpp │ ├── FileTypes.cpp │ ├── Filters.cpp │ ├── Fx.cpp │ ├── Game.cpp │ ├── GeometryStore.cpp │ ├── Grid.cpp │ ├── HeadlessOpenGLContext.cpp │ ├── HeadlessOpenGLContext.h │ ├── ImageLoading.cpp │ ├── LayerManipulation.cpp │ ├── MapExport.cpp │ ├── MapMerging.cpp │ ├── MapSavingLoading.cpp │ ├── MaterialExport.cpp │ ├── Materials.cpp │ ├── MessageBus.cpp │ ├── ModelExport.cpp │ ├── ModelScale.cpp │ ├── Models.cpp │ ├── Particles.cpp │ ├── Patch.cpp │ ├── PatchIterators.cpp │ ├── PatchWelding.cpp │ ├── PointTrace.cpp │ ├── Prefabs.cpp │ ├── RadiantTest.h │ ├── Registry.cpp │ ├── Renderer.cpp │ ├── SceneNode.cpp │ ├── SceneStatistics.cpp │ ├── Selection.cpp │ ├── SelectionAlgorithm.cpp │ ├── SelectionGroup.cpp │ ├── Settings.cpp │ ├── Skin.cpp │ ├── SoundManager.cpp │ ├── TdmMissionSetup.h │ ├── TerrainGenerator.cpp │ ├── TestContext.h │ ├── TestLogFile.h │ ├── TestOrthoViewManager.cpp │ ├── TestOrthoViewManager.h │ ├── TextureManipulation.cpp │ ├── TextureTool.cpp │ ├── Transformation.cpp │ ├── TrimTool.cpp │ ├── UndoRedo.cpp │ ├── VFS.cpp │ ├── WindingRendering.cpp │ ├── WorldspawnColour.cpp │ ├── XmlUtil.cpp │ ├── algorithm/ │ │ ├── Entity.h │ │ ├── FileUtils.h │ │ ├── Primitives.h │ │ ├── Scene.h │ │ ├── Selection.h │ │ ├── View.h │ │ └── XmlUtils.h │ ├── math/ │ │ ├── Matrix3.cpp │ │ ├── Matrix4.cpp │ │ ├── MatrixUtils.h │ │ ├── Plane3.cpp │ │ ├── Quaternion.cpp │ │ └── Vector.cpp │ ├── precompiled.cpp │ ├── precompiled.h │ ├── resources/ │ │ ├── fbx/ │ │ │ └── test_cube.fbx │ │ ├── map_loading_test.pk4 │ │ ├── settings/ │ │ │ ├── colours_incomplete.xml │ │ │ ├── colours_userdefined.xml │ │ │ └── old_favourites.xml │ │ ├── tdm/ │ │ │ ├── altar.pk4 │ │ │ ├── def/ │ │ │ │ ├── attribute_types.def │ │ │ │ ├── base.def │ │ │ │ ├── bucket.def │ │ │ │ ├── entity_with_model.def │ │ │ │ ├── func.def │ │ │ │ ├── gameplay.def │ │ │ │ ├── lights.def │ │ │ │ ├── lights_static.def │ │ │ │ ├── moveable.def │ │ │ │ ├── mover_door.def │ │ │ │ ├── player.def │ │ │ │ ├── skinned_models.def │ │ │ │ ├── speaker.def │ │ │ │ ├── tdm_ai.def │ │ │ │ └── tdm_frobable.def │ │ │ ├── fx/ │ │ │ │ └── parsertest.fx │ │ │ ├── guis/ │ │ │ │ ├── parse_test2.gui │ │ │ │ └── parse_test_include2.guicode │ │ │ ├── lights/ │ │ │ │ ├── squarelight1_amb.tga │ │ │ │ └── squarelight1a.tga │ │ │ ├── maps/ │ │ │ │ ├── ALTAr.lin │ │ │ │ ├── altar.darkradiant │ │ │ │ ├── altar_portalL_544_64_112.lin │ │ │ │ ├── fingerprinting.mapx │ │ │ │ ├── fingerprinting_2.mapx │ │ │ │ ├── general_purpose.mapx │ │ │ │ ├── layer_hierarchy_restore.darkradiant │ │ │ │ ├── layer_hierarchy_restore.mapx │ │ │ │ ├── merging_groups_1.mapx │ │ │ │ ├── merging_groups_2.mapx │ │ │ │ ├── merging_groups_3.mapx │ │ │ │ ├── merging_groups_4.mapx │ │ │ │ ├── merging_groups_5.mapx │ │ │ │ ├── merging_groups_6.mapx │ │ │ │ ├── merging_layers_1.mapx │ │ │ │ ├── merging_layers_2.mapx │ │ │ │ ├── merging_layers_3.mapx │ │ │ │ ├── merging_layers_4.mapx │ │ │ │ ├── merging_layers_5.mapx │ │ │ │ ├── patch_cap_test.mapx │ │ │ │ ├── selecting_filtered_items_with_layers.mapx │ │ │ │ ├── threeway_merge_base.mapx │ │ │ │ ├── threeway_merge_groups_base.mapx │ │ │ │ ├── threeway_merge_groups_source_1.mapx │ │ │ │ ├── threeway_merge_groups_target_1.mapx │ │ │ │ ├── threeway_merge_layers_source_1.mapx │ │ │ │ ├── threeway_merge_layers_target_1.mapx │ │ │ │ ├── threeway_merge_source_1.mapx │ │ │ │ ├── threeway_merge_source_2.mapx │ │ │ │ ├── threeway_merge_target_1.mapx │ │ │ │ ├── threeway_merge_target_2.mapx │ │ │ │ ├── twosided_ivy.mapx │ │ │ │ ├── weld_patches.mapx │ │ │ │ └── weld_patches2.mapx │ │ │ ├── materials/ │ │ │ │ ├── assets.lst │ │ │ │ ├── example.mtr │ │ │ │ ├── exporttest.mtr │ │ │ │ ├── frobstage.mtr │ │ │ │ ├── hidden.mtr │ │ │ │ ├── lights.mtr │ │ │ │ ├── null_byte_at_the_end.mtr │ │ │ │ ├── numbers.mtr │ │ │ │ ├── parsertest.mtr │ │ │ │ ├── parsing_test.mtr │ │ │ │ ├── pngs.mtr │ │ │ │ ├── tables.mtr │ │ │ │ ├── tdm_internal_engine.mtr │ │ │ │ ├── twosided.mtr │ │ │ │ └── z_precedence.mtr │ │ │ ├── models/ │ │ │ │ ├── ase/ │ │ │ │ │ ├── exploded_cube.ase │ │ │ │ │ ├── gauge_needle.ase │ │ │ │ │ ├── merged_cube.ase │ │ │ │ │ ├── separated_tiles.ase │ │ │ │ │ ├── single_triangle.ase │ │ │ │ │ ├── testcube.ase │ │ │ │ │ ├── testcube_no_ab_bc_ca_in_mesh_face.ase │ │ │ │ │ ├── testcube_no_smoothing_in_mesh_face.ase │ │ │ │ │ ├── testcube_uv_angle.ase │ │ │ │ │ ├── testcube_uv_offset.ase │ │ │ │ │ ├── testcube_uv_tiling.ase │ │ │ │ │ ├── testcube_without_material_ref.ase │ │ │ │ │ ├── testsphere.ase │ │ │ │ │ ├── tiles.ase │ │ │ │ │ ├── tiles_two_materials.ase │ │ │ │ │ ├── tiles_with_shared_vertex.ase │ │ │ │ │ └── tiles_with_shared_vertex_and_colour.ase │ │ │ │ ├── cube_with_usemtl.obj │ │ │ │ ├── md5/ │ │ │ │ │ ├── flag01.md5mesh │ │ │ │ │ ├── test_v11.md5mesh │ │ │ │ │ ├── test_v12.md5mesh │ │ │ │ │ └── testflag.md5mesh │ │ │ │ ├── missing_texture.ase │ │ │ │ ├── moss_patch.ase │ │ │ │ ├── torch.lwo │ │ │ │ └── twosided_ivy.lwo │ │ │ ├── particles/ │ │ │ │ ├── assets.lst │ │ │ │ ├── hiddenparticles.prt │ │ │ │ ├── testparticles.prt │ │ │ │ └── z_precedence.prt │ │ │ ├── prefabs/ │ │ │ │ └── large_bounds.pfbx │ │ │ ├── skins/ │ │ │ │ ├── selection_test.skin │ │ │ │ └── test_skins.skin │ │ │ ├── sound/ │ │ │ │ ├── assets.lst │ │ │ │ ├── hidden.sndshd │ │ │ │ ├── parsing_test.sndshd │ │ │ │ └── test/ │ │ │ │ └── jorge.ogg │ │ │ ├── tdm_example_mtrs.pk4 │ │ │ ├── test_decls.pk4 │ │ │ ├── test_models.pk4 │ │ │ ├── test_particles.pk4 │ │ │ ├── testdecls/ │ │ │ │ ├── exporttest.decl │ │ │ │ ├── numbers.decl │ │ │ │ ├── precedence_test1.decl │ │ │ │ ├── precedence_test2.decl │ │ │ │ ├── removal_tests.decl │ │ │ │ ├── syntax_parser_test1.decl │ │ │ │ ├── syntax_parser_test2.decl │ │ │ │ └── syntax_parser_test3.decl │ │ │ └── textures/ │ │ │ ├── a_1024x512.tga │ │ │ ├── dds/ │ │ │ │ ├── not_a_dds.dds │ │ │ │ ├── test_10x16_uncomp.dds │ │ │ │ ├── test_128x128_dxt1.dds │ │ │ │ ├── test_16x16_bc5.dds │ │ │ │ ├── test_16x16_uncomp.dds │ │ │ │ ├── test_16x16_uncomp_mips.dds │ │ │ │ ├── test_60x128_dxt5.dds │ │ │ │ └── test_60x128_dxt5_mips.dds │ │ │ └── numbers/ │ │ │ ├── 0.tga │ │ │ ├── 1.tga │ │ │ ├── 10.tga │ │ │ ├── 11.tga │ │ │ ├── 12.tga │ │ │ ├── 13.tga │ │ │ ├── 14.tga │ │ │ ├── 15.tga │ │ │ ├── 16.tga │ │ │ ├── 17.tga │ │ │ ├── 18.tga │ │ │ ├── 19.tga │ │ │ ├── 2.tga │ │ │ ├── 20.tga │ │ │ ├── 21.tga │ │ │ ├── 22.tga │ │ │ ├── 23.tga │ │ │ ├── 24.tga │ │ │ ├── 25.tga │ │ │ ├── 26.tga │ │ │ ├── 27.tga │ │ │ ├── 28.tga │ │ │ ├── 29.tga │ │ │ ├── 3.tga │ │ │ ├── 30.tga │ │ │ ├── 31.tga │ │ │ ├── 32.tga │ │ │ ├── 4.tga │ │ │ ├── 5.tga │ │ │ ├── 6.tga │ │ │ ├── 7.tga │ │ │ ├── 8.tga │ │ │ └── 9.tga │ │ └── xml/ │ │ ├── broken_file.xml │ │ ├── darkmod.game │ │ ├── input.xml │ │ └── testfile.xml │ └── testutil/ │ ├── CommandFailureHelper.h │ ├── FileSaveConfirmationHelper.h │ ├── FileSelectionHelper.h │ ├── MapOperationMonitor.h │ ├── RenderUtils.h │ ├── TemporaryFile.h │ ├── TestBufferObjectProvider.h │ ├── TestObjectRenderer.h │ ├── TestSyncObjectProvider.h │ └── ThreadUtils.h └── tools/ ├── DependencyCheck/ │ ├── DependencyCheck.vcxproj │ └── DependencyCheck.vcxproj.filters ├── i18n/ │ ├── build_pot.py │ └── darkradiant.pot ├── innosetup/ │ └── darkradiant.x64.iss ├── msvc/ │ ├── DarkRadiant.vcxproj │ ├── DarkRadiant.vcxproj.filters │ ├── DarkRadiantCore.vcxproj │ ├── DarkRadiantCore.vcxproj.filters │ ├── Tests/ │ │ ├── Tests.vcxproj │ │ ├── Tests.vcxproj.filters │ │ └── packages.config │ ├── dm.conversation.vcxproj │ ├── dm.conversation.vcxproj.filters │ ├── dm.difficulty.vcxproj │ ├── dm.difficulty.vcxproj.filters │ ├── dm.editing.vcxproj │ ├── dm.editing.vcxproj.filters │ ├── dm.gameconnection.vcxproj │ ├── dm.gameconnection.vcxproj.filters │ ├── dm.gui.vcxproj │ ├── dm.gui.vcxproj.filters │ ├── dm.objectives.vcxproj │ ├── dm.objectives.vcxproj.filters │ ├── dm.stimresponse.vcxproj │ ├── dm.stimresponse.vcxproj.filters │ ├── include.vcxproj │ ├── include.vcxproj.filters │ ├── libs.vcxproj │ ├── libs.vcxproj.filters │ ├── mathlib.vcxproj │ ├── mathlib.vcxproj.filters │ ├── modulelib.vcxproj │ ├── modulelib.vcxproj.filters │ ├── natvis/ │ │ └── mathlib.natvis │ ├── post_build_event_x64.cmd │ ├── properties/ │ │ ├── DarkRadiant Base Debug Win32.props │ │ ├── DarkRadiant Base Debug x64.props │ │ ├── DarkRadiant Base Release Win32.props │ │ ├── DarkRadiant Base Release x64.props │ │ ├── DarkRadiant Base.props │ │ ├── DarkRadiant Core Library.props │ │ ├── DarkRadiant Main Executable.props │ │ ├── DarkRadiant Module DLL.props │ │ ├── DarkRadiant Plugin DLL.props │ │ ├── DarkRadiant Static Library.props │ │ ├── GLEW.props │ │ ├── OpenAL + Vorbis.props │ │ ├── Python.props │ │ ├── Tests.props │ │ ├── ftgl.props │ │ ├── libgit2.props │ │ ├── libjpeg.props │ │ ├── libpng.props │ │ ├── wxWidgets.props │ │ └── zlib.props │ ├── scenelib.vcxproj │ ├── scenelib.vcxproj.filters │ ├── script.vcxproj │ ├── script.vcxproj.filters │ ├── sound.vcxproj │ ├── sound.vcxproj.filters │ ├── vcs.vcxproj │ ├── vcs.vcxproj.filters │ ├── wxutillib.vcxproj │ ├── wxutillib.vcxproj.filters │ └── xmlutillib.vcxproj ├── scripts/ │ ├── compile_release_package.ps1 │ ├── compile_release_package.x64.cmd │ ├── ddsinfo.py │ └── download_windeps.ps1 └── xcode/ ├── DarkRadiant App/ │ └── Info.plist ├── DarkRadiant.xcconfig ├── DarkRadiant.xcodeproj/ │ ├── project.pbxproj │ ├── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata/ │ └── xcschemes/ │ ├── DarkRadiant.xcscheme │ ├── DarkRadiantCore.xcscheme │ └── module.xcscheme ├── DarkRadiantCore.xcconfig ├── base.xcconfig ├── darkradiant.icns ├── dm.difficulty.xcconfig ├── dm.editing.xcconfig ├── eigen3.xcconfig ├── ftgl.xcconfig ├── glew.xcconfig ├── jpeg.xcconfig ├── libxml2.xcconfig ├── package_bundle.sh ├── picomodel.xcconfig ├── png.xcconfig ├── python.xcconfig ├── script.xcconfig ├── sigc++.xcconfig ├── sound.xcconfig ├── wxutil.xcconfig ├── wxwidgets.xcconfig └── zlib.xcconfig ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ # To learn more about .editorconfig see https://aka.ms/editorconfigdocs # All files [*] indent_style = space # Xml files [*.xml] indent_size = 4 ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto .gitattributes export-ignore .github export-ignore .gitlab-ci.yml export-ignore # Custom for Visual Studio *.cs diff=csharp *.sln merge=union *.csproj merge=union *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union # Standard to msysgit *.doc diff=astextplain *.DOC diff=astextplain *.docx diff=astextplain *.DOCX diff=astextplain *.dot diff=astextplain *.DOT diff=astextplain *.pdf diff=astextplain *.PDF diff=astextplain *.rtf diff=astextplain *.RTF diff=astextplain ================================================ FILE: .github/workflows/build.yml ================================================ name: Build on: [push] jobs: Windows-Build: runs-on: windows-latest env: # Path to the solution file relative to the root of the project. SOLUTION_FILE_PATH: .\DarkRadiant.sln TESTS_FILE_PATH: .\install\Tests.exe BUILD_CONFIGURATION: Release GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - uses: actions/checkout@v4 - name: Inject commit hash in version.h Header env: VERSION_HEADER_FILE: include\version.h SHA: ${{github.sha}} run: | $sha = $env:SHA.Substring(0, 7) Write-Host "Writing $sha to $env:VERSION_HEADER_FILE" $replaced = Get-Content $env:VERSION_HEADER_FILE | % { if ($_ -match '#define RADIANT_VERSION "((\d+.\d+.\d+)([\w\d]*))"') { $_.Replace($matches[1], $matches[2] + "_rev$sha") } else { $_ } }; $replaced | Out-File $env:VERSION_HEADER_FILE shell: powershell - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@v2 - name: Restore NuGet packages working-directory: ${{env.GITHUB_WORKSPACE}} run: nuget restore ${{env.SOLUTION_FILE_PATH}} - name: Build working-directory: ${{env.GITHUB_WORKSPACE}} run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:Platform=x64 /maxcpucount:4 /nodeReuse:false /p:UseSharedConfiguration=false ${{env.SOLUTION_FILE_PATH}} - name: Install Mesa openGL Drivers working-directory: ${{env.GITHUB_WORKSPACE}} env: UNIT_TEST_MESA_DRIVER_URL: https://github.com/codereader/DarkRadiant_WinDeps/releases/download/3.0.0/unit_test_mesa_driver-x64-20.1.8.7z run: | Write-Host ("Downloading Mesa driver package from {0}..." -f $env:UNIT_TEST_MESA_DRIVER_URL) $outFile = ".\install\unit_test_mesa_driver-x64.7z" Invoke-WebRequest $env:UNIT_TEST_MESA_DRIVER_URL -OutFile $outFile Write-Host ("Unpacking {0}..." -f $outFile) & .\tools\7z\7za.exe x $outFile -o".\install\" Get-ChildItem .\install\OpenGL32.dll shell: powershell - name: Setup VSTest.console.exe uses: darenm/Setup-VSTest@v1.3 - name: Run Unit Tests run: | FOR /F "tokens=* USEBACKQ" %%g IN (`powershell -Command "(Get-ChildItem -Recurse -Path 'C:\Program Files\Microsoft Visual Studio\' -Filter "GoogleTestAdapter.TestAdapter.dll" -ErrorAction SilentlyContinue).DirectoryName"`) do (SET "GTEST_ADAPTER_PATH=%%g") echo Test Adapter Path resolved to: %GTEST_ADAPTER_PATH% vstest.console.exe ${{env.TESTS_FILE_PATH}} /Platform:x64 /Logger:trx /TestAdapterPath:"%%GTEST_ADAPTER_PATH%%" shell: cmd - name: Generate Portable Package run: | echo Remove Mesa driver from output folder again del ..\..\install\OpenGL32.dll powershell -ExecutionPolicy ByPass .\compile_release_package.ps1 -Platform x64 -SkipBuild -GenerateSetupPackage:$false -GeneratePortablePackage:$false -OutputFolder ..\..\PortablePackage\ shell: cmd working-directory: .\tools\scripts - name: Upload Portable Package uses: actions/upload-artifact@v4 with: name: darkradiant-portable-package-x64 path: | tools/scripts/DarkRadiant_install.x64/**/* !tools/scripts/DarkRadiant_install.x64/**/*.pdb - name: Upload Portable Package PDBs uses: actions/upload-artifact@v4 with: name: darkradiant-pdb-files-x64 path: | tools/scripts/DarkRadiant_install.x64/**/*.pdb - name: Upload Test Results uses: actions/upload-artifact@v4 with: name: unit-test-results path: TestResults\*.trx Linux-Build: runs-on: ubuntu-latest env: BUILD_TYPE: Release steps: - uses: actions/checkout@v4 - name: Install Package Dependencies run: | sudo apt-get update sudo apt-get install -yq gettext pkg-config zlib1g-dev libjpeg-dev libxml2-dev libsigc++-2.0-dev sudo apt-get install -yq libgtest-dev libeigen3-dev libwxgtk3.2-dev libpng-dev sudo apt-get install -yq libftgl-dev libglew-dev libalut-dev libvorbis-dev python3-dev libgit2-dev libglib2.0-dev - name: Configure CMake # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system shell: bash run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=$GITHUB_WORKSPACE/install - name: Build env: CMAKE_BUILD_PARALLEL_LEVEL: 3 CTEST_OUTPUT_ON_FAILURE: ON shell: bash run: cmake --build . --config $BUILD_TYPE --target install ================================================ FILE: .gitignore ================================================ # Linux build files Makefile CMakeFiles CMakeCache.txt cmake_install.cmake /config.h /install_manifest.txt /radiant/darkradiant /install/darkradiant.desktop /test/drtest *.o *.lo *.so *.a *.la .deps # Linux profiling perf.data* # Doxygen output /dox # Editor temporary files *.swp tags # Windows directories w32deps w64deps build # Windows build files *.dll *.pdb install/*.exe tools/msvc/*.exe /tools/innosetup/*.exe *.exp *.lib # Image Source Files *.psd # Windows Visual Studio stuff *.user DarkRadiant.opensdf DarkRadiant.sdf gtkrc testsuite.ilk # VS Code .vscode .cache # VS /winbuild *.psess *.suo *.ipch *.dirstamp /tools/innosetup/*.7z *.vspx *.bak *.opendb *.iobj *.ipdb # Mac OS X Stuff .DS_Store xcuserdata /install/*.zip /tools/msvc/.vs /tools/msvc/DarkRadiant.VC.db /tools/innosetup/*.zip /tools/lwo_analyse/.vs /radiant/*.aps # Portable installation temp folders /tools/scripts/DarkRadiant_install.x64 /tools/scripts/DarkRadiant_install /install/*.ilk /tools/msvc/Tests/x64 /tools/msvc/x64 /tools/msvc/packages /install/*.testdurations *.ilk .vs/ windeps*.7z /packages /windeps ================================================ FILE: .gitlab-ci.yml ================================================ image: asciidoctor/docker-asciidoctor pages: stage: deploy script: - mkdir .public - asciidoctor -a stylesheet=manual.css -D .public $PWD/doc/manual.adoc - cp -r doc/img .public - mv .public/manual.html .public/index.html - gzip -k .public/index.html - mv .public public artifacts: paths: - public only: - master ================================================ FILE: AUTHORS ================================================ OrbWeaver greebo STiFU mohij angua Crispy Gildoran Jesps (Bulge patch algorithm) GtkRadiant CONTRIBUTORS and CREDITS last update: 09/12/2004 ======================= Loki ---- Leonardo Zide leo@lokigames.com Mike Phillips (Loki QA) Bernd Kreimeier (overall coordination) QER.com ------- TTimo timo@idsoftware.com ^Fishman (Pablo Zurita) fish@gamedesign.net RR2DO2 rr2do2@q3f.com SmallPileofGibs spog@planetquake.com Curry plugin ------------ Mike "mickey" Jackman Tim "Maj" Rennie PrtView plugin, various bug fixes and q3map guru ------------------------------------------------ Geoffrey DeWan Gensurf plugin -------------- David Hyde PicoModel --------- seaw0lf with assist by ydnar Q3Map2 ------ Randy 'ydnar' Reddig Updated shader files, textures, entities.def, keyboard shortcut list overall testing and feedback ---------------------------- Jean-Francois "Eutectic" Groleau Improvements and bug fixing --------------------------- Jan Paul "MrElusive" van Waveren Robert Duffy Forest "LordHavoc" Wroncy-Hale Nurail AcidDeath Chronos Michael Schlueter Jamie Wilkinson Robert "Tr3B" Beckebans Web --- Dave "Bargle" Koenig Jason "Wolfen" Spencer Shawn "EvilTypeGuy" Walker Thanks to John Hutton, AstroCreep and W2k for web help FAQ --- Equim and Wex Testing/Feedback --- Black_Dog, d0nkey, Fjoggis, Jago, jetscreamer, gibbie, Godmil, Gom Jabbar, Mindlink, mslaf, necros, Promit, Ravo, RPG, scampie, sock, sponge, thiste, voodoochopsticks, Zwiffle Misc ---- Thanks to everyone on the beta mailing list and irc.telefragged.com #qeradiant for testing and feedback. Updated icons by AstroCreep! Bitch-slapping by RaYGunn! Last minute bugs by SPoG! (SPoG--) ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.12) # Project name and version project(darkradiant VERSION 3.9.2) # C++ standard set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED True) # GCC 8 and earlier require explicit linking against stdc++fs if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) link_libraries(stdc++fs) endif() # Expose some build options option(ENABLE_DM_PLUGINS "Build Dark Mod specific plugins" ON) option(ENABLE_GIT_PLUGIN "Build the Git VCS integration plugin" ON) option(ENABLE_RELOCATION "Avoid hard-coded absolute paths to libraries or resources" ON) # Define GNU-style directory structure by default include(GNUInstallDirs) # Set up core build paths set(CORE_MODULE_LIBRARY "libradiantcore") set(PKGDATADIR "${CMAKE_INSTALL_FULL_DATADIR}/darkradiant") set(PKGLIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}/darkradiant") if (${ENABLE_RELOCATION}) set(RELATIVE_LIBDIR "../${CMAKE_INSTALL_LIBDIR}/darkradiant") else() set(HTMLDIR "${CMAKE_INSTALL_FULL_DATADIR}/doc/darkradiant") endif() # Build shared libraries by default option(BUILD_SHARED_LIBS "Build shared libraries" ON) if (${ENABLE_RELOCATION}) set(CMAKE_INSTALL_RPATH "$ORIGIN/${RELATIVE_LIBDIR}") else() set(CMAKE_INSTALL_RPATH "${PKGLIBDIR}") endif() # Debug or release mode if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() add_compile_definitions( $<$:_DEBUG> $<$:NDEBUG> ) # Locate system packages include(FindPkgConfig) pkg_check_modules(SIGC sigc++-2.0 REQUIRED) pkg_check_modules(FTGL ftgl REQUIRED) pkg_check_modules(FREETYPE freetype2 REQUIRED) pkg_check_modules(GL gl REQUIRED) pkg_check_modules(GLEW glew REQUIRED) pkg_check_modules(JPEG libjpeg REQUIRED) pkg_check_modules(PNG libpng REQUIRED) pkg_check_modules(AL openal REQUIRED) pkg_check_modules(OGG ogg REQUIRED) pkg_check_modules(VORBIS vorbisfile REQUIRED) pkg_check_modules(X11 x11 REQUIRED) pkg_check_modules(ZLIB zlib REQUIRED) pkg_check_modules(GLIB glib-2.0 REQUIRED) pkg_check_modules(EIGEN eigen3 REQUIRED) # Locate a packaged pugixml, if installed if not, fall back to embedded code copy. find_package(pugixml QUIET) if (TARGET pugixml::pugixml) message(NOTICE "Distribution pugixml found and used.") else() include_directories(libs/pugixml) endif() # Locate wxWidgets find_package(wxWidgets REQUIRED COMPONENTS base core stc adv gl xrc aui) include(${wxWidgets_USE_FILE}) # Locate Python find_package(Python REQUIRED COMPONENTS Development) # Global includes and flags include_directories(libs libs/libfmt include) add_compile_options(${SIGC_CFLAGS}) add_compile_definitions(POSIX WXINTL_NO_GETTEXT_MACRO FMT_HEADER_ONLY HAVE_STD_FILESYSTEM) add_link_options(LINKER:-z,defs) # Generate config.h configure_file(config.h.in config.h) add_compile_definitions(HAVE_CONFIG_H) include_directories(${CMAKE_CURRENT_BINARY_DIR}) # Set up a usable installation tree within the binary dir so developers don't # have to install to a temporary location set(DR_STAGING_ROOT "${CMAKE_BINARY_DIR}/darkradiant") set(DR_STAGING_LIBDIR "${DR_STAGING_ROOT}/lib/darkradiant") set(DR_STAGING_MODULESDIR "${DR_STAGING_LIBDIR}/modules") set(DR_STAGING_PLUGINSDIR "${DR_STAGING_LIBDIR}/plugins") set(DR_STAGING_DATADIR "${DR_STAGING_ROOT}/share/darkradiant") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${DR_STAGING_ROOT}/bin") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${DR_STAGING_LIBDIR}") # Supporting libraries add_subdirectory(libs/math) add_subdirectory(libs/xmlutil) add_subdirectory(libs/scene) add_subdirectory(libs/wxutil) add_subdirectory(libs/module) # Mandatory modules add_subdirectory(plugins/script) add_subdirectory(plugins/sound) # Optional Git plugin if (${ENABLE_GIT_PLUGIN}) pkg_check_modules(LIBGIT libgit2) if (${LIBGIT_FOUND}) add_subdirectory(plugins/vcs) endif() endif() # Dark Mod plugins if (${ENABLE_DM_PLUGINS}) add_subdirectory(plugins/dm.conversation) add_subdirectory(plugins/dm.stimresponse) add_subdirectory(plugins/dm.objectives) add_subdirectory(plugins/dm.difficulty) add_subdirectory(plugins/dm.editing) add_subdirectory(plugins/dm.gui) add_subdirectory(plugins/dm.gameconnection) endif() # Main radiant components add_subdirectory(radiantcore) add_subdirectory(radiant) # Tests pkg_check_modules(GTEST gtest) pkg_check_modules(GTEST_MAIN gtest_main) if (${GTEST_FOUND} AND ${GTEST_MAIN_FOUND}) enable_testing() add_subdirectory(test) endif() # Documentation find_program(ASCIIDOCTOR asciidoctor) if (ASCIIDOCTOR) add_subdirectory(doc) else() message(WARNING "asciidoctor not found; documentation will not be generated") endif() # Install targets include(install.cmake) ================================================ FILE: DarkRadiant.sln ================================================ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.9.34728.123 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DarkRadiant", "tools\msvc\DarkRadiant.vcxproj", "{8E70385C-223A-4DD1-9B99-28FF2331A2B5}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mathlib", "tools\msvc\mathlib.vcxproj", "{3C9FB5AA-7118-476E-B33D-D3AC1C8412BB}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xmlutillib", "tools\msvc\xmlutillib.vcxproj", "{A15EFB56-927F-411D-A57B-0328321456A2}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxutillib", "tools\msvc\wxutillib.vcxproj", "{B6D4B38A-0C39-42CD-8193-75979E1F4D68}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} = {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} {F7408B46-E4A9-470C-9731-9A1564247385} = {F7408B46-E4A9-470C-9731-9A1564247385} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sound", "tools\msvc\sound.vcxproj", "{1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {B6D4B38A-0C39-42CD-8193-75979E1F4D68} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.stimresponse", "tools\msvc\dm.stimresponse.vcxproj", "{EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {B6D4B38A-0C39-42CD-8193-75979E1F4D68} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.objectives", "tools\msvc\dm.objectives.vcxproj", "{05E9A613-2108-4843-A567-16B432DAC272}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {B6D4B38A-0C39-42CD-8193-75979E1F4D68} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.difficulty", "tools\msvc\dm.difficulty.vcxproj", "{68B95079-09DF-48F7-BAD9-81C33118BEFD}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} = {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scenelib", "tools\msvc\scenelib.vcxproj", "{F7408B46-E4A9-470C-9731-9A1564247385}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "include", "tools\msvc\include.vcxproj", "{41CAAD78-9E48-4C6E-B8F8-A04A859C16F9}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.conversation", "tools\msvc\dm.conversation.vcxproj", "{435F29EA-7236-49AD-BF1A-5DB8AD566B5D}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {A15EFB56-927F-411D-A57B-0328321456A2} = {A15EFB56-927F-411D-A57B-0328321456A2} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "script", "tools\msvc\script.vcxproj", "{979A38FE-BE30-4121-845C-B705461BB1B0}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.editing", "tools\msvc\dm.editing.vcxproj", "{3552912C-32C9-4D59-9E65-357AD147A1FC}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.gui", "tools\msvc\dm.gui.vcxproj", "{586DBC32-C9D4-4720-B246-1E3D7D8C02B3}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libs", "tools\msvc\libs.vcxproj", "{5EB15BCF-2131-4DE3-B411-FC0D2DEF702F}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Static Libraries", "Static Libraries", "{026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Modules", "Modules", "{3C3C0B81-D1B7-4EE4-9224-99ECA5774F25}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main Binary and Headers", "Main Binary and Headers", "{F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DarkRadiantCore", "tools\msvc\DarkRadiantCore.vcxproj", "{83D79C71-4E8F-4F78-9D46-EF02D5D5CD89}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} = {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215} = {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215} {A15EFB56-927F-411D-A57B-0328321456A2} = {A15EFB56-927F-411D-A57B-0328321456A2} {F7408B46-E4A9-470C-9731-9A1564247385} = {F7408B46-E4A9-470C-9731-9A1564247385} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "modulelib", "tools\msvc\modulelib.vcxproj", "{76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tests", "tools\msvc\Tests\Tests.vcxproj", "{20C43725-BD6F-4E90-8D8C-5AB2AFFBF957}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89} = {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dm.gameconnection", "tools\msvc\dm.gameconnection.vcxproj", "{471AEAFE-68CE-4010-9B8F-3CB95810BEA5}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {B6D4B38A-0C39-42CD-8193-75979E1F4D68} {F7408B46-E4A9-470C-9731-9A1564247385} = {F7408B46-E4A9-470C-9731-9A1564247385} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DependencyCheck", "tools\DependencyCheck\DependencyCheck.vcxproj", "{0D4BE190-97F4-4DB9-BEAB-B0196868EC0A}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vcs", "tools\msvc\vcs.vcxproj", "{6591C1E2-6BCF-4874-B724-CC87B8AA0DA4}" ProjectSection(ProjectDependencies) = postProject {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} {A15EFB56-927F-411D-A57B-0328321456A2} = {A15EFB56-927F-411D-A57B-0328321456A2} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {B6D4B38A-0C39-42CD-8193-75979E1F4D68} EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {8E70385C-223A-4DD1-9B99-28FF2331A2B5}.Debug|x64.ActiveCfg = Debug|x64 {8E70385C-223A-4DD1-9B99-28FF2331A2B5}.Debug|x64.Build.0 = Debug|x64 {8E70385C-223A-4DD1-9B99-28FF2331A2B5}.Release|x64.ActiveCfg = Release|x64 {8E70385C-223A-4DD1-9B99-28FF2331A2B5}.Release|x64.Build.0 = Release|x64 {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB}.Debug|x64.ActiveCfg = Debug|x64 {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB}.Debug|x64.Build.0 = Debug|x64 {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB}.Release|x64.ActiveCfg = Release|x64 {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB}.Release|x64.Build.0 = Release|x64 {A15EFB56-927F-411D-A57B-0328321456A2}.Debug|x64.ActiveCfg = Debug|x64 {A15EFB56-927F-411D-A57B-0328321456A2}.Debug|x64.Build.0 = Debug|x64 {A15EFB56-927F-411D-A57B-0328321456A2}.Release|x64.ActiveCfg = Release|x64 {A15EFB56-927F-411D-A57B-0328321456A2}.Release|x64.Build.0 = Release|x64 {B6D4B38A-0C39-42CD-8193-75979E1F4D68}.Debug|x64.ActiveCfg = Debug|x64 {B6D4B38A-0C39-42CD-8193-75979E1F4D68}.Debug|x64.Build.0 = Debug|x64 {B6D4B38A-0C39-42CD-8193-75979E1F4D68}.Release|x64.ActiveCfg = Release|x64 {B6D4B38A-0C39-42CD-8193-75979E1F4D68}.Release|x64.Build.0 = Release|x64 {1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F}.Debug|x64.ActiveCfg = Debug|x64 {1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F}.Debug|x64.Build.0 = Debug|x64 {1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F}.Release|x64.ActiveCfg = Release|x64 {1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F}.Release|x64.Build.0 = Release|x64 {EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F}.Debug|x64.ActiveCfg = Debug|x64 {EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F}.Debug|x64.Build.0 = Debug|x64 {EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F}.Release|x64.ActiveCfg = Release|x64 {EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F}.Release|x64.Build.0 = Release|x64 {05E9A613-2108-4843-A567-16B432DAC272}.Debug|x64.ActiveCfg = Debug|x64 {05E9A613-2108-4843-A567-16B432DAC272}.Debug|x64.Build.0 = Debug|x64 {05E9A613-2108-4843-A567-16B432DAC272}.Release|x64.ActiveCfg = Release|x64 {05E9A613-2108-4843-A567-16B432DAC272}.Release|x64.Build.0 = Release|x64 {68B95079-09DF-48F7-BAD9-81C33118BEFD}.Debug|x64.ActiveCfg = Debug|x64 {68B95079-09DF-48F7-BAD9-81C33118BEFD}.Debug|x64.Build.0 = Debug|x64 {68B95079-09DF-48F7-BAD9-81C33118BEFD}.Release|x64.ActiveCfg = Release|x64 {68B95079-09DF-48F7-BAD9-81C33118BEFD}.Release|x64.Build.0 = Release|x64 {F7408B46-E4A9-470C-9731-9A1564247385}.Debug|x64.ActiveCfg = Debug|x64 {F7408B46-E4A9-470C-9731-9A1564247385}.Debug|x64.Build.0 = Debug|x64 {F7408B46-E4A9-470C-9731-9A1564247385}.Release|x64.ActiveCfg = Release|x64 {F7408B46-E4A9-470C-9731-9A1564247385}.Release|x64.Build.0 = Release|x64 {41CAAD78-9E48-4C6E-B8F8-A04A859C16F9}.Debug|x64.ActiveCfg = Debug|x64 {41CAAD78-9E48-4C6E-B8F8-A04A859C16F9}.Debug|x64.Build.0 = Debug|x64 {41CAAD78-9E48-4C6E-B8F8-A04A859C16F9}.Release|x64.ActiveCfg = Release|x64 {41CAAD78-9E48-4C6E-B8F8-A04A859C16F9}.Release|x64.Build.0 = Release|x64 {435F29EA-7236-49AD-BF1A-5DB8AD566B5D}.Debug|x64.ActiveCfg = Debug|x64 {435F29EA-7236-49AD-BF1A-5DB8AD566B5D}.Debug|x64.Build.0 = Debug|x64 {435F29EA-7236-49AD-BF1A-5DB8AD566B5D}.Release|x64.ActiveCfg = Release|x64 {435F29EA-7236-49AD-BF1A-5DB8AD566B5D}.Release|x64.Build.0 = Release|x64 {979A38FE-BE30-4121-845C-B705461BB1B0}.Debug|x64.ActiveCfg = Debug|x64 {979A38FE-BE30-4121-845C-B705461BB1B0}.Debug|x64.Build.0 = Debug|x64 {979A38FE-BE30-4121-845C-B705461BB1B0}.Release|x64.ActiveCfg = Release|x64 {979A38FE-BE30-4121-845C-B705461BB1B0}.Release|x64.Build.0 = Release|x64 {3552912C-32C9-4D59-9E65-357AD147A1FC}.Debug|x64.ActiveCfg = Debug|x64 {3552912C-32C9-4D59-9E65-357AD147A1FC}.Debug|x64.Build.0 = Debug|x64 {3552912C-32C9-4D59-9E65-357AD147A1FC}.Release|x64.ActiveCfg = Release|x64 {3552912C-32C9-4D59-9E65-357AD147A1FC}.Release|x64.Build.0 = Release|x64 {586DBC32-C9D4-4720-B246-1E3D7D8C02B3}.Debug|x64.ActiveCfg = Debug|x64 {586DBC32-C9D4-4720-B246-1E3D7D8C02B3}.Debug|x64.Build.0 = Debug|x64 {586DBC32-C9D4-4720-B246-1E3D7D8C02B3}.Release|x64.ActiveCfg = Release|x64 {586DBC32-C9D4-4720-B246-1E3D7D8C02B3}.Release|x64.Build.0 = Release|x64 {5EB15BCF-2131-4DE3-B411-FC0D2DEF702F}.Debug|x64.ActiveCfg = Debug|x64 {5EB15BCF-2131-4DE3-B411-FC0D2DEF702F}.Debug|x64.Build.0 = Debug|x64 {5EB15BCF-2131-4DE3-B411-FC0D2DEF702F}.Release|x64.ActiveCfg = Release|x64 {5EB15BCF-2131-4DE3-B411-FC0D2DEF702F}.Release|x64.Build.0 = Release|x64 {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89}.Debug|x64.ActiveCfg = Debug|x64 {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89}.Debug|x64.Build.0 = Debug|x64 {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89}.Release|x64.ActiveCfg = Release|x64 {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89}.Release|x64.Build.0 = Release|x64 {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215}.Debug|x64.ActiveCfg = Debug|x64 {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215}.Debug|x64.Build.0 = Debug|x64 {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215}.Release|x64.ActiveCfg = Release|x64 {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215}.Release|x64.Build.0 = Release|x64 {20C43725-BD6F-4E90-8D8C-5AB2AFFBF957}.Debug|x64.ActiveCfg = Debug|x64 {20C43725-BD6F-4E90-8D8C-5AB2AFFBF957}.Debug|x64.Build.0 = Debug|x64 {20C43725-BD6F-4E90-8D8C-5AB2AFFBF957}.Release|x64.ActiveCfg = Release|x64 {20C43725-BD6F-4E90-8D8C-5AB2AFFBF957}.Release|x64.Build.0 = Release|x64 {471AEAFE-68CE-4010-9B8F-3CB95810BEA5}.Debug|x64.ActiveCfg = Debug|x64 {471AEAFE-68CE-4010-9B8F-3CB95810BEA5}.Debug|x64.Build.0 = Debug|x64 {471AEAFE-68CE-4010-9B8F-3CB95810BEA5}.Release|x64.ActiveCfg = Release|x64 {471AEAFE-68CE-4010-9B8F-3CB95810BEA5}.Release|x64.Build.0 = Release|x64 {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A}.Debug|x64.ActiveCfg = Debug|x64 {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A}.Debug|x64.Build.0 = Debug|x64 {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A}.Release|x64.ActiveCfg = Release|x64 {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A}.Release|x64.Build.0 = Release|x64 {6591C1E2-6BCF-4874-B724-CC87B8AA0DA4}.Debug|x64.ActiveCfg = Debug|x64 {6591C1E2-6BCF-4874-B724-CC87B8AA0DA4}.Debug|x64.Build.0 = Debug|x64 {6591C1E2-6BCF-4874-B724-CC87B8AA0DA4}.Release|x64.ActiveCfg = Release|x64 {6591C1E2-6BCF-4874-B724-CC87B8AA0DA4}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {8E70385C-223A-4DD1-9B99-28FF2331A2B5} = {F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D} {3C9FB5AA-7118-476E-B33D-D3AC1C8412BB} = {026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA} {A15EFB56-927F-411D-A57B-0328321456A2} = {026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA} {B6D4B38A-0C39-42CD-8193-75979E1F4D68} = {026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA} {1482AAB4-40B6-44C0-9FD8-AF80C18A5E7F} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {EE9A3B61-58E0-4AA4-8942-6CFCBFAACC3F} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {05E9A613-2108-4843-A567-16B432DAC272} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {68B95079-09DF-48F7-BAD9-81C33118BEFD} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {F7408B46-E4A9-470C-9731-9A1564247385} = {026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA} {41CAAD78-9E48-4C6E-B8F8-A04A859C16F9} = {F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D} {435F29EA-7236-49AD-BF1A-5DB8AD566B5D} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {979A38FE-BE30-4121-845C-B705461BB1B0} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {3552912C-32C9-4D59-9E65-357AD147A1FC} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {586DBC32-C9D4-4720-B246-1E3D7D8C02B3} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {5EB15BCF-2131-4DE3-B411-FC0D2DEF702F} = {F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D} {83D79C71-4E8F-4F78-9D46-EF02D5D5CD89} = {F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D} {76FF9B0F-B1FF-42BF-9E1D-8FBE2B3F6215} = {026C3BBE-9A3B-4D21-A49D-12DD9DDF3CBA} {471AEAFE-68CE-4010-9B8F-3CB95810BEA5} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} {0D4BE190-97F4-4DB9-BEAB-B0196868EC0A} = {F0E8C46B-4F20-43B1-9A8D-13A9D0A3BA3D} {6591C1E2-6BCF-4874-B724-CC87B8AA0DA4} = {3C3C0B81-D1B7-4EE4-9224-99ECA5774F25} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {C7F73C9B-AFA1-4AF0-9F99-7C3A7F503A86} EndGlobalSection EndGlobal ================================================ FILE: Doxyfile ================================================ # Doxyfile 1.5.3 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file that # follow. The default is UTF-8 which is also the encoding used for all text before # the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into # libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of # possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = DarkRadiant # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = dox # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = YES # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, # Italian, Japanese, Japanese-en (Japanese with English messages), Korean, # Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, # Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the DETAILS_AT_TOP tag is set to YES then Doxygen # will output the detailed description near the top, like JavaDoc. # If set to NO, the detailed description appears after the member # documentation. DETAILS_AT_TOP = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for Java. # For instance, namespaces will be presented as packages, qualified scopes # will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to # include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be extracted # and appear in the documentation as a namespace called 'anonymous_namespace{file}', # where file will be replaced with the base name of the file that contains the anonymous # namespace. By default anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. SHOW_DIRECTORIES = NO # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from the # version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = include libs radiant plugins # This tag can be used to specify the character encoding of the source files that # doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default # input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. # See http://www.gnu.org/software/libiconv for the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py FILE_PATTERNS = # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = plugins/dm.d3hook/boost \ plugins/dm.d3hook/RCF \ plugins/dm.d3hook/SF \ libs/libfmt \ libs/pybind # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the output. # The symbol name can be a fully qualified name, a word, or if the wildcard * is used, # a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. If you have enabled CALL_GRAPH or CALLER_GRAPH # then you must also enable this option. If you don't then doxygen will produce # a warning and turn it on anyway SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES (the default) # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES (the default) # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. Otherwise they will link to the documentstion. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side panel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, # Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are # probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = YES # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = YES # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. This is useful # if you want to understand what is going on. On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = YES # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to # produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to # specify the directory where the mscgen tool resides. If left empty the tool is assumed to # be found in the default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = NO # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = NO # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = NO # If the CALL_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a call dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected # functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH, SOURCE_BROWSER and HAVE_DOT tags are set to YES then doxygen will # generate a caller dependency graph for every global function or class method. # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected # functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = NO # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the number # of direct children of the root node in a graph is already larger than # MAX_DOT_GRAPH_NOTES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, which results in a white background. # Warning: Depending on the platform used, enabling this option may lead to # badly anti-aliased labels on the edges of a graph (i.e. they become hard to # read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES #--------------------------------------------------------------------------- # Configuration::additions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO ================================================ FILE: GPL ================================================ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ================================================ FILE: LICENSE ================================================ DarkRadiant License (last update: 2024-03-08) ---------------------------------------------------------------------------------------------- DarkRadiant is free software originally based on GtkRadiant, which has been licensed under the GNU General Public License (GPLv2) http://www.gnu.org/licenses/gpl-2.0.html Therefore all of the DarkRadiant source code (save a few exceptions noted below) is published under the same GPLv2 license. Unless stated otherwise in the source file header, the following applies to the DarkRadiant source code: DarkRadiant - Open Source Level Editor for Doom 3 and The Dark Mod Copyright (C) 2024 Matthias Baumann (on behalf of the DarkRadiant Team, see AUTHORS file) ========================================================================================== This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA ========================================================================================== Exceptions to the above ---------------------------------------------------------------------------------------------- PicoModel Library - published under the modified Berkeley Software Distribution (BSD) license DDS Library - published under the modified Berkeley Software Distribution (BSD) license pybind11 Library - see the LICENSE file in the libs/pybind folder fmtlib Library - see the LICENSE file in the libs/libfmt folder (BSD 2-clause "Simplified" License) OpenFBX library - see the LICENSE file in radiantcore/model/import/openfbx (MIT license) pugixml library - see the LICENSE file in the libs/pugixml folder (MIT license) SHA256 implementation - by Brad Conte, released into the public domain, see this URL: (https://github.com/B-Con/crypto-algorithms/tree/master#readme) ================================================ FILE: NEWS ================================================ ================================================ FILE: PKGBUILD ================================================ # Maintainer: codereader pkgname=darkradiant pkgver=3.8.0 pkgrel=1 pkgdesc="Level Editor for Doom 3 (idTech4) and The Dark Mod" arch=("x86_64") url="https://www.darkradiant.net/" license=("GPL") depends=(wxgtk2 ftgl glew freealut libvorbis python libsigc++ eigen) makedepends=(cmake git) source=("$pkgname::git+https://github.com/codereader/DarkRadiant.git#tag=3.8.0") md5sums=("SKIP") build() { cd "$pkgname" cmake . make } package() { cd "$pkgname" make DESTDIR="$pkgdir/" install } ================================================ FILE: README.md ================================================ DarkRadiant Logo # DarkRadiant DarkRadiant is a level (map) editor for the **The Dark Mod**, an open-source Doom 3 modification which is available at www.thedarkmod.com. Its primary use is creating missions for The Dark Mod as well as maps for idTech4-based games like Doom 3, Quake 4 and Prey. ## Download Get the latest DarkRadiant binaries from the [releases page](https://github.com/codereader/DarkRadiant/releases/latest). We have binaries for Windows and macOS, plus [compilation instructions](https://wiki.thedarkmod.com/index.php?title=DarkRadiant_-_Compiling_in_Linux) for various Linux distributions. # Getting started DarkRadiant requires game resources to work with, these resources are not installed by this editor. You'll need to point DarkRadiant to one of these games (The Dark Mod, Doom 3, Quake 4, etc.) before you can start to work on your map. Visit [www.thedarkmod.com](https://www.thedarkmod.com) for download instructions, then proceed with one of the tutorials available on the web. For The Dark Mod mappers, there are a couple of [Video Tutorials](https://wiki.thedarkmod.com/index.php?title=DarkRadiant_Video_Tutorials) on the project's wiki, which should get you started. # Compiling on Windows ## Prerequisites DarkRadiant is built on Windows using *Microsoft Visual Studio*, the free Community Edition can be obtained here: *VC++ 2022:* https://visualstudio.microsoft.com/downloads/ (Choose Visual Studio Community) When installing Studio please make sure to enable the "Desktop Development with C++" workload. ## Build The main Visual C++ solution file is located in the root folder of this repository: `DarkRadiant.sln` Open this file with Visual Studio and start a build by right-clicking on the top-level "Solution 'DarkRadiant'" item and choosing Build Solution. The `DarkRadiant.exe` file will be placed in the `install/` folder. ### Windows Build Dependencies Since DarkRadiant requires a couple of open-source libraries that are not available on Windows by default, it will try to download and install the dependencies when the build starts. If it fails for some reason, you can try to run this script: `tools/scripts/download_windeps.ps1` or extract the tools manually, downloading the 7-Zip package containing the necessary files from the URL below ([Get 7-zip here](https://www.7-zip.org/)): https://github.com/codereader/DarkRadiant_WinDeps/releases/latest/ The dependencies packages need to be extracted into the main DarkRadiant source directory, i.e. alongside the `include/` and `radiant/` directories. Just drop the windeps.7z in the DarkRadiant folder and use 7-zip's "Extract to here" # Compiling on Linux ## Prerequisites To compile DarkRadiant a number of libraries (with development headers) and a standards-compliant C++17 compiler are required. On an Ubuntu system the requirements may include any or all of the following packages: * zlib1g-dev * libjpeg-dev * libwxgtk3.0-dev * libxml2-dev * libsigc++-2.0-dev * libpng-dev * libftgl-dev * libglew-dev * libalut-dev * libvorbis-dev * libgtest-dev * libeigen3-dev * libgit2-dev (optional) To generate the local offline HTML user guide, the `asciidoctor` command must be in your PATH. This is an optional dependency: if the command is not found, the CMake build will proceed without building the user guide. This does not include core development tools such as g++ or the git client to download the sources (use sudo apt-get install git for that). One possible set of packages might be: `sudo apt-get install git cmake g++ gettext pkg-config` More required package lists for various Linux distributions are [listed in the Wiki Article](https://wiki.thedarkmod.com/index.php?title=DarkRadiant_-_Compiling_in_Linux). ## Build To build DarkRadiant the standard CMake build process is used: ``` cmake . make sudo make install ``` To install somewhere other than the default of `/usr/local`, use the `CMAKE_INSTALL_PREFIX` variable. ``` cmake -DCMAKE_INSTALL_PREFIX=/opt/darkradiant make sudo make install ``` Other useful variables are `CMAKE_BUILD_TYPE` to choose Debug or Release builds, `ENABLE_DM_PLUGINS` to disable the building of Dark Mod specific plugins (enabled by default), and `ENABLE_RELOCATION` to control whether DarkRadiant uses hard-coded absolute paths like `/usr/lib` or paths relative to the binary (useful for certain package formats like Snappy or FlatPak). # Compiling on macOS ## Prerequisites You'll need an Xcode version supporting C++17 and the macOS 10.15 (Catalina) target at minimum. Xcode 11.3 should be working fine. You will need to install the Xcode command line tools to install MacPorts (run `xcode-select --install`) To compile DarkRadiant, a number of libraries (with development headers) are required. You can obtain them by using [MacPorts](https://distfiles.macports.org/MacPorts/): Install MacPorts, then open a fresh console and issue these commands: ``` sudo port install jpeg wxwidgets-3.0 pkgconfig libsigcxx2 freetype ftgl glew sudo port install libxml2 freealut libvorbis libogg openal-soft eigen3 ``` ## Build Start Xcode and open the project file in `tools/xcode/DarkRadiant.xcodeproj`. Hit CMD-B to start the build, the output files will be placed to a folder similar to this: `~/Library/Developer/Xcode/DerivedData/DarkRadiant-somethingsomething/Build/Products/Release` The `DarkRadiant.app` package in that folder can be launched right away or copied to some location of your preference. # More Build Information A more detailed compilation guide can be found on The Dark Mod's wiki: https://wiki.thedarkmod.com/index.php?title=DarkRadiant_-_Compilation_Guide # Contact / Discussion DarkRadiant Website: https://www.darkradiant.net All discussion is ongoing primarily at [The Dark Mod Forums](https://forums.thedarkmod.com/forum/51-darkradiant-feedback-and-development/), where you can get in touch with knowledgeable people and discuss changes or issues. If you happen to run into a bug, you're encouraged to report it to us, especially when running into application crashes (see also [How to record a crashdump](https://wiki.thedarkmod.com/index.php?title=Save_a_Memory_Dump_for_debugging_Crashes)). The issue tracker for DarkRadiant is also run by the Dark Mod folks: [DarkRadiant Bugtracker](https://bugs.thedarkmod.com/view_all_bug_page.php?project_id=1). # License The DarkRadiant source code is published under the [GNU General Public License 2.0 (GPLv2)](http://www.gnu.org/licenses/gpl-2.0.html ), except for a few libraries which are using the BSD or MIT licenses, see the [LICENSE](https://raw.githubusercontent.com/codereader/DarkRadiant/master/LICENSE) file for specifics. ================================================ FILE: config.h.in ================================================ /* Core module file, e.g. "libradiantcore" */ #cmakedefine CORE_MODULE_LIBRARY "@CORE_MODULE_LIBRARY@" /* Project version */ #define PACKAGE_VERSION "@CMAKE_PROJECT_VERSION@" /* Defined if this is a relocatable build */ #cmakedefine ENABLE_RELOCATION /* Locale directory */ #define LOCALEDIR "@CMAKE_INSTALL_FULL_LOCALEDIR@" /* Package library directory (e.g. /usr/lib/darkradiant) */ #cmakedefine PKGLIBDIR "@PKGLIBDIR@" /* Relative library directory from binary (e.g. ../lib/darkradiant). Only * defined if ENABLE_RELOCATION is defined. */ #cmakedefine RELATIVE_LIBDIR "@RELATIVE_LIBDIR@" /* Package data directory (e.g. /usr/share/darkradiant) */ #cmakedefine PKGDATADIR "@PKGDATADIR@" /* HTML directory (e.g. /usr/share/doc/darkradiant) */ #cmakedefine HTMLDIR "@HTMLDIR@" ================================================ FILE: darkradiant.spec ================================================ Name: darkradiant Version: 0.9.12 Release: 2%{?dist} Summary: Level editor for Doom 3 and The Dark Mod Group: Applications/Editors License: GPLv2 and LGPLv2 and BSD URL: http://darkradiant.sourceforge.net/ Source0: %{name}-%{version}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) BuildRequires: automake, autoconf, libtool, desktop-file-utils %description DarkRadiant is a 3D level editor for Doom 3 and The Dark Mod, based on the GPL release of GtkRadiant. %prep %setup -q %build %configure --enable-darkmod-plugins --enable-debug --prefix=/usr make %{?_smp_mflags} %install rm -rf $RPM_BUILD_ROOT make install DESTDIR=$RPM_BUILD_ROOT desktop-file-install \ --dir=${RPM_BUILD_ROOT}%{_datadir}/applications \ ${RPM_BUILD_ROOT}%{_datadir}/applications/darkradiant.desktop %clean rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root,-) %doc README %{_bindir}/* %{_libdir}/darkradiant/lib* %{_libdir}/darkradiant/modules %{_libdir}/darkradiant/scripts %{_libdir}/darkradiant/plugins/eclasstree* %{_datadir}/* %package plugins-darkmod Summary: DarkMod-specific plugins for DarkRadiant Group: Applications/Editors Requires: darkradiant %description plugins-darkmod These plugins are used for editing Dark Mod missions. %files plugins-darkmod %defattr(-,root,root,-) %doc README.linux %{_libdir}/darkradiant/plugins/dm_* %changelog * Tue Mar 26 2009 ibix - 0.9.12-2 - patches upstream. Removed here. * Tue Mar 24 2009 ibix - 0.9.12-1 - spec file. - patch for sound detection on fedora. - patch for valid desktop entry. ================================================ FILE: debian/README ================================================ The Debian Package darkradiant ---------------------------- Comments regarding the Package -- orbweaver Sat, 21 Jun 2008 15:25:20 +0100 ================================================ FILE: debian/changelog ================================================ darkradiant (3.9.2~jammy1) jammy; urgency=medium * Fix incorrect preview rendering of vertex blends between pairs of diffuse and bump maps. * Fix inability to choose source and replacement materials using the Skin Editor GUI. * Several additional layout and usability improvements to Skin Editor. * Improvements to layout and organisation of Preferences dialog; consolidate a few pages and remove obsolete items. * Add a new preference to control the font size of text in the various source code editors. * Fix wxGTK assertion failure on opening Stim/Response editor. -- Matthew Mott Mon, 19 Aug 2024 19:24:12 +0100 darkradiant (3.9.1~jammy1) jammy; urgency=medium * Textures with RGTC normal maps no longer show as black in lighting preview mode. * Skin editor no longer crashes when editing the skin name. * Reduced space wastage in Surface Editor. * Several dialogs which could previously be shrunk to zero size no longer do so. -- Matthew Mott Sat, 25 May 2024 13:10:46 +0100 darkradiant (3.9.0~jammy1) jammy; urgency=medium * Add "Show definition" button for the "inherit" spawnarg. * Preserve patch tesselation fixed subdivisions when creating caps. * Add Filters for Location Entities and Player Start. * Support saving entity key/value pairs containing double quotes. * Allow a way to easily see all properties of attached entities. * Ortho views preserve their orientation between sessions. * Various bug fixes and minor improvements. -- Matthew Mott Tue, 02 Apr 2024 20:26:39 +0100 darkradiant (3.8.0~jammy1) jammy; urgency=medium * New feature: Support new frob-related material keywords. * Mission selection list in Game setup is now alphabetically sorted. * Better distinction between inherited and regular spawnargs. * Silence sound shader button. * Add Reload Definitions button to Model Chooser. * Various bug fixes and minor improvements. -- Matthew Mott Tue, 07 Feb 2023 20:34:04 +0000 darkradiant (3.7.0~jammy1) jammy; urgency=medium * New feature: Skin Editor * Script Window usability improvements * Various bug fixes. -- Matthew Mott Wed, 11 Jan 2023 20:29:21 +0000 darkradiant (3.6.0~jammy1) jammy; urgency=medium * New Selection Focus feature (Ctrl-F). * Add Radiant.findEntityByName script method. * Media Browser shows a thumbnail preview when selecting folders. * Map is remembering layer visibilities between loads. -- Matthew Mott Tue, 15 Nov 2022 20:28:13 +0000 darkradiant (3.5.0~jammy1) jammy; urgency=medium * More customisable layout: all windows and panes can be dragged and re-arranged. Legacy layouts like Embedded, Regular and Splitpane are superseded and removed. * The LayerControlPanel's tooltip popup is now less annoying. * Clarify distinction between Shadow render mode and other render modes * Show/hide Light Volumes for combined entities inconsistent. * Currently applied particleDef not selected in Particle Selector. * Layer visibility checkbox not reacting to double-clicks. * Cannot toggle visibility of layers in Linux. * Drag-and-dropping layers is not working in Linux. -- Matthew Mott Tue, 08 Nov 2022 19:52:10 +0000 darkradiant (3.4.0~jammy1) jammy; urgency=medium * Layers can now be organised into a tree rather than a flat list. * Several bug fixes. -- Matthew Mott Tue, 11 Oct 2022 20:11:03 +0100 darkradiant (3.3.0~jammy1) jammy; urgency=medium * New FX chooser and support for parsing FX declarations. * Numerous menu entries greyed out when not currently available. * Certain menu entries and UI elements hidden when not available in current game. * Renderer now handles "translucent" keyword. * Lighting mode renderer now draws hidden lights. * Several minor bugfixes. -- Matthew Mott Tue, 27 Sep 2022 19:53:22 +0100 darkradiant (3.2.0~jammy1) jammy; urgency=medium * Show entityDefs related to selected models in Model Chooser. * Support for rendering blend lights. * Implement sorting of Interaction Stages. * Recognise type of "set x on y" spawnargs. * OBJ files: loader supports usemtl keywords directly referencing material names (without .mtl file). * Numerous bug fixes and improvements. -- Matthew Mott Tue, 06 Sep 2022 20:27:52 +0100 darkradiant (3.1.0~jammy1) jammy; urgency=medium * Texture Tool now supports free scaling with the mouse. * Improved robustness and correctness of decl handling. * Numerous fixes to Material Editor. * Improve Model Export dialog and workflow. * Other fixes and improvements. -- Matthew Mott Tue, 23 Aug 2022 20:49:18 +0100 darkradiant (3.0.0~focal1) focal; urgency=medium * New major release on all platforms * Significant improvements to performance and functionality of renderer, including shadow support. * Numerous small fixes and improvements. -- Matthew Mott Wed, 15 Jun 2022 20:39:03 +0100 darkradiant (2.14.0~focal2) focal; urgency=medium * New major release on all platforms. * Multi-selection support in Entity Inspector. * New model importer with ability to import FBX models. * Improved copy-paste of textures on angled faces. * Improved scaling functionality in Surface Inspector. * Redesigned Game Connection UI to enable hot reload in The Dark Mod. * Numerous smaller fixes and improvements. -- Matthew Mott Sun, 28 Nov 2021 18:52:23 +0000 darkradiant (2.13.0~focal4) focal; urgency=medium * Fix for incorrect entity/brush colours in canvas windows. -- Matthew Mott Tue, 24 Aug 2021 19:45:54 +0100 darkradiant (2.13.0~focal1) focal; urgency=medium * New major release on all platforms. * Git integration with three-way map comparison and diffing. * Ability to choose between several different pointfiles. * Improved workflow for adjusting light brightness. * Entity Inspector can show editor_usage information. * BC5/RGTC normal map support. * Aspect ratio-preserving Fit Texture option. * Shader selector can show material definitions. * Restore texture browser ability to show variable size thumbnails. * Numerous other bug fixes and improvements. -- Matthew Mott Tue, 10 Aug 2021 19:41:21 +0100 darkradiant (2.12.0~focal3) focal; urgency=medium * Include resources needed by the Material Editor preview. -- Matthew Mott Tue, 04 May 2021 19:35:53 +0100 darkradiant (2.12.0~focal2) focal; urgency=medium * New major release on all platforms. * Add a customisable UI layout using wxAUI. * New material editor for visual editing of material definitions. * Renderer improvements: entities with attached lights now render as lights, and ambient lights display correctly regardless of surface orientation. * New 3D grid feature. * Add a script to detect duplicated objects. * Various bug fixes and improvements. -- Matthew Mott Mon, 03 May 2021 13:39:18 +0100 darkradiant (2.11.0~focal2) focal; urgency=medium * New favourites system for assets like entities, textures and sound shaders. * Improved text search in resource browsers. * Ability to list model definitions in model chooser. * Initial GUI improvements to game connection plugin. * Various bug fixes. -- Matthew Mott Fri, 29 Jan 2021 20:36:34 +0000 darkradiant (2.10.0~focal1) focal; urgency=medium * New major release on all platforms. * Introduce ability to merge/connect adjacent patches. * Maps can now be loaded from within PK4 resource packages. * Font family and size can be adjusted in 2D views (grid coordinates etc). * Colour scheme can override light volume colour (instead of using the _color spawnarg) in 2D views. * New warning if overwriting map file which has been modified since loading (e.g. by another DarkRadiant instance). * Numerous bug fixes and minor UI improvements. -- Matthew Mott Sat, 26 Dec 2020 19:39:52 +0000 darkradiant (2.9.1~focal5) focal; urgency=medium * First package built using the new CMake build system. * Fix an assertion failure on showing the Stim/Response editor. * Introduce preference to set the font and size of numeric text in the 2D view. * Maps can now be loaded directly from within the PK4 resource tree. -- Matthew Mott Thu, 10 Dec 2020 15:43:35 +0000 darkradiant (2.9.1~focal1) focal; urgency=medium * 2.9.1 release for Focal. * Includes the new GameConnection functionality for The Dark Mod, as well as numerous bug fixes and improvements. -- Matthew Mott Tue, 24 Nov 2020 19:36:02 +0000 darkradiant (2.7.0) bionic; urgency=medium * 2.7.0 release for Bionic. -- Matthew Mott Tue, 14 Jan 2020 21:37:34 +0000 darkradiant (2.6.0) bionic; urgency=medium * 2.6.0 release for Bionic. * This feature release is further improving on the Model Exporting capabilities and introduces smaller features like a mapping time stopwatch and the ability to define favourites in the Media Browser, making it more convenient to work with a large number of materials. -- Matthew Mott Fri, 18 Jan 2019 20:17:22 +0000 darkradiant (2.0.2-2~vivid1) vivid; urgency=medium * Entity list now shows entity names, and no longer crashes when an entity is selected. -- Matthew Mott Thu, 24 Sep 2015 22:58:44 +0100 darkradiant (2.0.2-1~vivid1) vivid; urgency=medium * 2.0.2 release for Vivid. -- Matthew Mott Fri, 28 Aug 2015 22:43:48 +0100 darkradiant (2.0.2) trusty; urgency=medium * New upstream release. -- Matthew Mott Mon, 12 Jan 2015 18:48:28 +0000 darkradiant (2.0.1-1~trusty1) trusty; urgency=medium * Fix for crash/assertion when trying to show Add Property dialog. * Added .game file for The Dark Mod standalone that does not include a base/ subdirectory. * Various other bugfixes. -- Matthew Mott Wed, 24 Dec 2014 14:41:12 +0000 darkradiant (2.0.1~trusty2) trusty; urgency=low * 2.0 series release for Linux, including the switch from GTK to wxWidgets. * 2.0.1 contains numerous bug-fixes over the original 2.0 version. -- Matthew Mott Mon, 17 Nov 2014 19:55:17 +0000 darkradiant (1.8.0~trusty1) trusty; urgency=low * This release contains numerous bug and stability fixes as well as one new feature for flooring objects. Some improvements have also been made to better support different game types. * Fix for patch mesh rendering on nVidia hardware with recent drivers. -- Matthew Mott Sat, 28 Jun 2014 10:02:35 +0100 darkradiant (1.7.3~raring1) raring; urgency=low * Fixed progressive corruption of non-worldspawn brush geometry over multiple save operations (#3272) -- Matthew Mott Sat, 02 Feb 2013 09:15:03 +0000 darkradiant (1.7.2~raring1) raring; urgency=low * Fixed incorrect renaming of entities when importing a map (#2733). -- Matthew Mott Mon, 22 Oct 2012 18:35:36 +0100 darkradiant (1.7.1~raring2) raring; urgency=low * Fixed black render artifacts in model preview window (#2939). * Fixed lighting view turning black when certain models are in view (#2969). * Fixed crash on exit after changing view layout (#2954). * Fixed sky box textures failing to render. * Fixed inability to move vertices with arrow keys in camera view (#2938). * Fixed crash after Save As in Particle Editor (now renamed to Copy to better reflect its behaviour). * Fixed crash in Readables editor if certain font resources were missing from the mod assets tree. * Re-designed model chooser allows control over visibility of model's component materials. * Improved performance of map loading and population of certain asset tree views (#2987). * Splitter position in certain dialogs is persistent. * Linux build does not fail if GtkSourceView is not available, this is now an optional dependency. * Updated GTK and related library versions on Windows (#2945) -- Matthew Mott Sun, 13 May 2012 11:25:18 +0100 darkradiant (1.7.0.1~raring1) raring; urgency=low * Fixed possible crash in displaying particle editor on Linux. * Fixed failure to find user-local mod assets in (e.g.) ~/.doom3/darkmod -- Matthew Mott Tue, 29 Nov 2011 19:51:12 +0000 darkradiant (1.7.0~raring1) raring; urgency=low * 1.7.0 release. -- Matthew Mott Mon, 14 Nov 2011 11:13:41 +0000 ================================================ FILE: debian/compat ================================================ 10 ================================================ FILE: debian/control ================================================ Source: darkradiant Section: editors Priority: optional Maintainer: Matthew Mott Build-Depends: debhelper (>= 10), cmake (>= 3.12), pkg-config, asciidoctor, libxml2-dev, libglew-dev, python3-dev, libvorbis-dev, libopenal-dev, libalut-dev, libjpeg-dev, libftgl-dev, libwxgtk3.2-dev, libsigc++-2.0-dev, libglib2.0-dev, libeigen3-dev, libgit2-dev Homepage: https://www.darkradiant.net/ Vcs-Git: https://gitlab.com/orbweaver/DarkRadiant.git Standards-Version: 4.5.1 Package: darkradiant Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Description: Level editor for Doom 3 and The Dark Mod DarkRadiant is a 3D level editor for Doom 3 and The Dark Mod, based on the GPL release of GtkRadiant. Package: darkradiant-plugins-darkmod Architecture: any Depends: darkradiant, ${shlibs:Depends}, ${misc:Depends} Description: DarkMod-specific plugins for DarkRadiant These plugins are used for editing Dark Mod missions. Package: darkradiant-plugin-git Architecture: any Depends: darkradiant, ${shlibs:Depends}, ${misc:Depends} Description: Git integration plugin for DarkRadiant This plugin allows DarkRadiant to integrate with Git version control. Package: darkradiant-i18n Architecture: any Depends: darkradiant, ${misc:Depends} Description: Internationalisation files for DarkRadiant. This package includes the translated strings for localising DarkRadiant into different languages. The currently-available languages are: . de (German) ================================================ FILE: debian/copyright ================================================ Copyright Notice: © 2006 - 2010 OrbWeaver , greebo & other DarkRadiant authors listed below. © 2006 GtkRadiant authors listed below. Authors: DarkRadiant portions: OrbWeaver greebo STiFU mohij angua Crispy Gildoran Jesps (Bulge patch algorithm) GtkRadiant portions: Leonardo Zide leo@lokigames.com Mike Phillips (Loki QA) Bernd Kreimeier (overall coordination) TTimo timo@idsoftware.com ^Fishman (Pablo Zurita) fish@gamedesign.net RR2DO2 rr2do2@q3f.com SmallPileofGibs spog@planetquake.com Mike "mickey" Jackman Tim "Maj" Rennie Geoffrey DeWan David Hyde seaw0lf with assist by ydnar Randy 'ydnar' Reddig Jean-Francois "Eutectic" Groleau Jan Paul "MrElusive" van Waveren Robert Duffy Forest "LordHavoc" Wroncy-Hale Nurail AcidDeath Chronos Michael Schlueter Jamie Wilkinson Robert "Tr3B" Beckebans Licence: This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This package is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this package; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA On Debian systems, the complete text of the GNU General Public License can be found in `/usr/share/common-licenses/GPL'. ================================================ FILE: debian/darkradiant-i18n.install ================================================ usr/share/locale ================================================ FILE: debian/darkradiant-plugin-git.install ================================================ usr/lib/*/darkradiant/plugins/libvcs* ================================================ FILE: debian/darkradiant-plugins-darkmod.install ================================================ usr/lib/*/darkradiant/plugins/libdm_* ================================================ FILE: debian/darkradiant.install ================================================ usr/bin usr/lib/*/darkradiant/lib* usr/lib/*/darkradiant/modules usr/share/darkradiant/scripts usr/share/darkradiant usr/share/doc/darkradiant usr/share/applications usr/share/icons usr/share/metainfo ================================================ FILE: debian/darkradiant.manpages ================================================ man/darkradiant.1 ================================================ FILE: debian/dirs ================================================ usr/bin usr/lib usr/share ================================================ FILE: debian/docs ================================================ README.md ================================================ FILE: debian/rules ================================================ #!/usr/bin/make -f %: dh $@ override_dh_auto_configure: dh_auto_configure -- -DENABLE_RELOCATION:BOOL=OFF override_dh_auto_test: true override_dh_shlibdeps: dh_shlibdeps -l/usr/lib/darkradiant ================================================ FILE: debian/source/format ================================================ 3.0 (native) ================================================ FILE: doc/CMakeLists.txt ================================================ set(DR_STAGING_DOCDIR "${DR_STAGING_ROOT}/share/doc/darkradiant") add_custom_command( OUTPUT manual.html COMMAND ${ASCIIDOCTOR} ARGS -a stylesheet=manual.css -D ${DR_STAGING_DOCDIR} ${CMAKE_CURRENT_SOURCE_DIR}/manual.adoc DEPENDS manual.adoc ) add_custom_target(doc ALL DEPENDS manual.html) # Copy the images into the staging directory for local preview file(GLOB_RECURSE DOC_IMAGES img/*.png) execute_process( COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/img ${DR_STAGING_DOCDIR}/img ) # Installation at package time install(FILES ${DR_STAGING_DOCDIR}/manual.html DESTINATION ${CMAKE_INSTALL_DOCDIR}) install(DIRECTORY img DESTINATION ${CMAKE_INSTALL_DOCDIR} FILES_MATCHING PATTERN "*.png") ================================================ FILE: doc/manual.adoc ================================================ = DarkRadiant User Guide :toc: left :toclevels: 3 :imagesdir: img :icons: :iconsdir: img == Introduction DarkRadiant is a level editor for Doom 3 and The Dark Mod, developed by The Dark Mod team. It may also be used for editing levels for similar *id Software* games such as Quake 4. This User Guide describes the features and functionality of DarkRadiant, however it is not intended as a guide to mapping techniques. Level design is a complex topic, and is covered by various other learning resources, some of which are listed below. http://wiki.thedarkmod.com/index.php?title=Main_Page[The Dark Mod Wiki]:: The starting point for most Dark Mod documentation and tutorials, including gameplay, configuration and editing. https://modwiki.xnet.fi[ModWiki]:: Online wiki covering editing topics for vanilla Doom 3 and similar engines. http://forums.thedarkmod.com[The Dark Mod forums]:: Online community for discussion of the Dark Mod, including various ad-hoc mapping tutorial threads posted by individual users. === Editing workflow image::DarkRadiantWorkflow.png[align="center"] The level editing process starts off with basic assets: models, textures, sounds, entity definitions, skins, animations and so on. Many of these assets will be packaged with a particular game installation, but a level designer may also choose to create custom assets for a specific mission. These assets are installed into a directory tree which is accessible both by DarkRadiant (for editing) and the game engine itself (for playing the mission). Once assets have been arranged in DarkRadiant according to the wishes of the level designer, a `.map` file is saved to disk. This is a text file in a format understood by the game engine, and includes both level geometry and references to the assets used in the map. Since the `.map` file is simply text, and does not actually embed the binary asset data, it tends to be fairly small. The game engine includes functionality to _compile_ the `.map` file into a `.proc` file containing low-level vertex geometry derived from the brushes and patches within the `.map` file. The game engine can then render the mission in realtime, making use of the same assets that were accessed by DarkRadiant during editing. DarkRadiant also maintains its own separate file containing various editing information, such as object layers used within a map. This `.darkradiant` file is never used by the game engine, and is non-critical -- a `.map` file with no accompanying `.darkradiant` file can still be edited with DarkRadiant, although certain DarkRadiant-specific state may be lost. === What's in a MAP? There are three main types of object contained within a `.map` file: entities, brushes and patches. *Entities* are the top-level objects in a map -- essentially, a map file is just a list of entities. Every entity has an *entity class* which determines the type of entity it is: static mesh, AI, sound emitter, particle emitter, light etc. Entities also store a list of string key/value pairs, known as *spawnargs* or *properties*. Some entities also contain brushes and patches as children. *Brushes* are convex solids used to define basic map geometry: walls, floors, ceilings, steps and other medium to large items. Brushes are often rectangular in shape, although a brush can actually have any number of faces provided that it is convex (it is impossible to have a brush in an L or a U shape, for example). Brushes are not smooth-shaded by the game engine, which generally makes them unsuitable for representing curved surfaces. *Patches* are smooth one-sided surfaces used to represent curved objects such as vaulted ceilings, pillars or cave interiors. A patch is defined by a number of Bezier control points, and offers control over the level of detail used when subdividing the patch into triangles for rendering: more triangles will produce a smoother surface but may lower rendering performance. Brushes and patches together are also referred to as *primitives* (since they define the basic geometry of the map), and are typically described as such in situations where the distinction between brush and patch is not important. The entities, brushes and patches in a map are arranged in a hierarchy: not every entity has children, but every primitive must have an entity as a parent. Each map therefore starts with a single default entity called the *worldspawn*, which acts as the parent for new brushes and patches created in DarkRadiant. == Initial configuration [[GameSetup]] === Choosing a game type When running DarkRadiant for the first time, the *Game Setup* dialog will be shown. This is where you configure the path to the game installation from which DarkRadiant will load assets, such as textures, models and entity definitions. image::GameSetupDialog.png[align="center"] The *Game Setup* dialog contains the following options: *Game Type*:: DarkRadiant ships with support for several different game engines, each of which is contained within a `.game` file. For editing Dark Mod missions, the default choice of `The Dark Mod 2.0 (Standalone)` is the one to use, but it is also possible to edit stock Doom 3 or Quake 4 missions. *DarkMod Path* / *Engine Path*:: This is the path to the game installation on the system. The label text will change depending on whether the selected game is `The Dark Mod` or another engine. *Mission*:: Optional path to a subdirectory containing assets specific to a particular mission which is being worked on. For game types other than `The Dark Mod`, this will be displayed as *Mod (fs_game)*, and should be set to the path of a subdirectory containing a particular game mod, if one is being used. *Mod Base (fs_game_base)*:: This field only appears for non-DarkMod game types. It allows a two-level mod structure, where the *Mod Base* can point to a major game mod, possibly downloaded from elsewhere, while *Mod* can be set to point to an entirely local "sub-mod" which contains local changes and overrides. Before the release of Dark Mod standalone, this field would have been set to `darkmod` while the *Mod* field would have been set to the local mission, however this is no longer necessary when `The Dark Mod 2.0 (Standalone)` is being used. Once the game paths are set up, click the *Save* button to proceed to the main DarkRadiant interface. NOTE: It is possible to *Cancel* the *Game Setup* dialog and proceed to the main window without configuring a game installation, in which case DarkRadiant will show a warning and ask if you wish to proceed. If you do, DarkRadiant will run but there will be no available textures, models, entities or other game assets. === Interface layout DarkRadiant uses a flexible layout system based on dockable windows which can be moved into various positions around the edges of the main window, or floated as separate top-level windows. The arrangement and sizes of these windows are saved into settings and persisted between sessions. Each window has a small title bar at the top showing the window's name. Dragging this title bar will allow the docked window to be floated or docked into a different position depending on the drag destination. When the window is dragged near a possible dock position, a shaded rectangle will appear indicating where the window will be docked. There is a central 2D view which cannot be undocked or replaced, although it can be made arbitrarily small by expanding docked widgets towards the center. Likewise, the camera view and properties panels cannot be removed, although they can be resized and moved into different dock positions. You can create _additional_ 2D and camera views using the *View -> New XY view* and *View -> New Camera view* menu items. These additional views can be floated or docked like the main windows, and can also be removed by clicking the *X* button at the top right of the title bar. All 2D views store their orientation (XY/YZ/XZ) into settings, which makes it possible to set up a traditional 3D modelling interface with three orthographic views and a camera view, if desired. [[ColourSchemes]] === Colour schemes DarkRadiant defaults to a black-on-white colour scheme in the 2D windows, but ships with four other colour schemes, which can be chosen with the *View -> Colours...* dialog. If you prefer a dark theme, the `Black & Green` scheme might be suitable, whereas the `Maya/Max/Lightwave Emulation` and `Super Mal` themes provide a more neutral, low-contrast look. Colour schemes only affect what is rendered in the 2D and 3D views by DarkRadiant itself. The appearance of the user interface is determined by the *wxWidgets* toolkit based on the system-wide widget theme, and can only be changed via system settings or other applications (such as `gnome-tweaks` on Linux). [align="center",cols="^.` origin position, if visible within the view. .Components of the 2D view image::2DViewMarkedUp.png[align="center"] The 2D view also shows the current position of the camera (used for rendering the separate 3D camera view window), and its view direction. The following commands are available within the 2D view: [cols="1h,3"] |=== |Right drag|Scroll the view horizontally or vertically |Mouse wheel|Zoom the view |Shift + Right drag|Zoom the view (alternative binding) |Ctrl + Middle click|Move the camera directly to the clicked position |Middle click|Rotate the camera to look directly at the clicked point |Ctrl + TAB|Change view axis (XY, XZ, YZ) |Ctrl + Shift + TAB|Center 2D view on current camera position |=== === Adjusting the grid The grid shown in the 2D view is used to snap the position and size of brushes and patches, as well as the centerpoints of entities. The size of the grid can be configured, in powers of 2, from 0.125 up to 256, using the *1-9* keys on the main keyboard (not the numeric keypad), or the equivalent options in the *Grid* menu. The *0* key on the main keyboard can be used to toggle the display of the grid. Note that objects will still be snapped to the grid even if the grid is not visible; this is purely a visual toggle. IMPORTANT: Level geometry built from brushes and patches should _always_ be snapped to the grid to avoid problems such as rendering glitches and map leaks. Static meshes and animated AI can be positioned more freely, however grid snapping is a useful tool for ensuring that models are appropriately aligned with the level geometry. ==== Customising the grid appearance The appearance of the grid can be customised using the options in the *Grid* tab of the *Edit -> Preferences* dialog. Separate styles can be chosen for major and minor grid lines. [align="center",cols="^. Background image...* which will show the background image configuration dialog. *Use background image*:: Master toggle to show or hide the background image. *Image file*:: Click on the widget to show a file chooser which allows you to find and select the background image to show. *Opacity*:: Drag the slider to control the opacity of the image, from fully transparent (invisible) to fully opaque. *Scale*:: Adjusts the size of the image. *Horiz. offset*:: Adjusts the position of the image from left to right. *Vert. offset*:: Adjusts the position of the image from top to bottom. *Keep aspect*:: If checked, the image will always be displayed at its native aspect ratio. If unchecked, the image will have the same aspect ratio as the containing 2D view. *Zoom with viewport*:: If checked, the image will change size as the 2D view is zoomed in or out. If unchecked, the image will always have the same size regardless of the 2D window zoom. *Pan with viewport*:: If checked, the image will be anchored in 2D space, and will stay in the same position relative to the world as the 2D view is panned. If unchecked, the image will always have the same position relative to the window, and the world geometry will pan around it. [[Using3DCameraView]] === Using the 3D camera view The 3D camera view provides an approximate rendering of the map in three dimensions, in several different render modes: wireframe, flat shaded, textured, and fully lit by in-game light sources. While the 2D view is the main interface for creating and aligning level geometry, the 3D view is a vital tool for tasks such as texturing, or configuring light parameters. IMPORTANT: The fully lit rendering mode in DarkRadiant is not identical to what the game engine will ultimately render. Certain advanced rendering features such as reflections and fog lights are not currently supported. The 3D camera view provides its own toolbar which can be used to configure various display settings. [cols="^1h,3h,10"] |=== 3+^h|Render modes |image:wireframeMode16.png[align="center",width=24]|Render in wireframe mode| Render objects as wire meshes. |image:solidMode16.png[align="center",width=24]|Render in flat-shaded mode| Render objects as coloured solids, without textures or lighting. |image:textureMode16.png[align="center",width=24]|Render in fullbright textured mode| Render objects as preview textures, with no lighting or material effects such as transparency. |image:lightingMode.png[align="center",width=24]|Render in lighting preview mode| Render all available lighting and texture effects. |image:lightingModeWithShadows.png[align="center",width=24]|Toggle shadow rendering| Enable the rendering of shadows when in lighting preview mode. 3+^h|Animation rendering |image:StartPlayback.png[align="center",width=24]|Start render time| Begin rendering animated effects. |image:StopPlayback.png[align="center",width=24]|Stop render time| Stop rendering animated effects. 3+^h|Far clip options |image:toggleFarClip.png[align="center",width=24]|Toggle far clip| Enable or disable the far clip plane. The far clip plane is a performance optimisation which avoids rendering geometry more than a certain distance away from the camera. |image:farClipIn.png[align="center",width=24]|Clip plane in| Move the far clip plane closer to the camera. |image:farClipOut.png[align="center",width=24]|Clip plane out| Move the far clip plane further away from the camera. |=== The 3D view always renders the scene from a particular camera position, which is shown in the 2D view as a blue diamond. This camera position can be set directly from the 2D view with *Ctrl + Middle click*, and the camera view direction can be set with *Middle click*. There are also various options within the 3D view itself to adjust the camera position. [cols="1h,3"] |=== |Right click|Enter or leave free camera mode. In this mode, moving the mouse around updates the camera view direction in real-time, and moving the mouse around while holding *Ctrl* causes the camera to move up/down/left/right according to the camera motion. 2+^h|Default mode (not free camera) |Left/Right arrow|Pan the camera left or right |Up/Down arrow|Move the camera forwards or backwards on the horizontal plane, without changing its height on the Z axis. 2+^h|Free camera mode |Left/Right arrow|Move ("truck") camera left or right, leaving view direction the same. |Up/Down arrow|Move ("dolly") the camera forwards or backwards along its view axis |=== === Manipulating objects Every object in a map can be selected and moved within the 2D view. Some objects -- including brushes, patches and lights -- can also be resized. For more advanced ways to select objects, see <>. [cols="1h,3"] |=== |Shift + Left click|Select or deselect the object at the clicked position. Any existing selected objects will remain selected. If the clicked position overlaps more than one object, the closest one (according to the current 2D view axis) will be affected. |Alt + Shift + Left click|Select the object at the clicked position, and deselect any existing selected objects. If the clicked position overlaps more than one object, each click will cycle through the overlapping objects. |Shift + Left drag|Draw a selection rectangle, which will select any objects contained (fully or partially) within it. |ESC|Deselect all objects |Left drag (_inside_ object)|Move the selected object(s) |Left drag (_outside_ object)|Resize the selected object(s) (if available) |Space|Duplicate the selected object(s) |Backspace|Delete the selected object(s) |=== TIP: Like other editors in the Radiant family, DarkRadiant offers a rather unusual system for resizing objects. Rather than clicking exactly on the edge, or on a dedicated resizing handle, you can click and drag anywhere outside an edge to move that edge inwards or outwards. Dragging outside a corner allows you to move two edges at once. ==== Flipping and rotating DarkRadiant provides six buttons to quickly flip or rotate objects (in 90 degree increments) around each of the three world axes. These are available on the left-hand vertical toolbar. [cols="^1h,10"] |=== |image:brush_flipx.png[align="center",width=24]|Flip along the X axis |image:brush_rotatex.png[align="center",width=24]|Rotate around the X axis |image:brush_flipy.png[align="center",width=24]|Flip along the Y axis |image:brush_rotatey.png[align="center",width=24]|Rotate around the Y axis |image:brush_flipz.png[align="center",width=24]|Flip along the Z axis |image:brush_rotatez.png[align="center",width=24]|Rotate around the Z axis |=== [[ManipulatorModes]] ==== Manipulator modes For more precise control over object motion, there are three manipulator modes which can be selected with buttons on the left-hand vertical toolbar. [cols="^1h,3h,10"] |=== |image:select_mousetranslate.png[align="center",width=24]|Translate mode| A manipulator widget with axis-aligned arrows will be displayed at the selected object's center. Click and drag one of the arrows to move the object along that axis, or drag inside the manipulator box to move the object in two dimensions. This mode may be useful for moving brushes around without accidentally resizing them. |image:select_mouserotate.png[align="center",width=24]|Rotate mode| A widget with three axis-aligned rings will be displayed at the selected object's center. Drag a ring to rotate the object by any arbitrary amount around that ring's axis. |image:select_mouseresize.png[align="center",width=24]|Resize mode| This is the default Radiant drag mode (hence the "QE" icon referring to the original QERadiant) which allows you to move objects by dragging inside them and resize by dragging outside the boundary edges. |=== === Working with brushes Brushes are the basic building blocks of all maps. Typically they are used for coarse-grained level geometry such as walls, ceiling and floors. Brushes also have a vital role in sealing a map from the void: even a map built entirely from patches and static meshes must still be surrounded by brushes in order to avoid leaking. .Additive versus subtractive geometry **** If you are used to mapping for the legacy Thief games using Dromed or T3Edit, the system used by DarkRadiant may seem somewhat back-to-front. In previous games, the world starts out as an infinite solid, in which you "carve out" rooms using subtractive brushes. In DarkRadiant, the world starts out as an infinite void, and all brushes are solid. The space in which the mission happens must be fully enclosed by solid brushes, otherwise the map will "leak" and fail to compile. The need to deal with map leaks may at first seem like a burden, however the exclusive use of solid brushes frees the engine from needing to worry about "brush ordering", and allows an important performance optimisation: by "flood filling" the map interior, the map compiler can efficiently discard geometry that never needs to be rendered. **** [[CreatingABrush]] ==== Creating a brush To create a simple rectangular brush, ensure that nothing is selected (*ESC*), then *Left drag* in the 2D view. A new brush will be created and sized according to the dragged area, with its dimensions snapped to the current grid level. To adjust the third dimension of the brush (perpendicular to the view direction), used *Ctrl + TAB* to switch the 2D view axis, and *Left drag* outside the brush boundary to adjust the size. TIP: Whenever you drag to create a new brush, the third dimension will match the size of the _most recently selected_ brush. This makes it easy to draw a series of brushes with the same height, such as when you need to create a series of floors or walls in succession. To match the height of an existing brush, simply select (*Shift + Left click*) and deselect it (*ESC*) before drawing the new brush. [[BrushShapes]] ==== More complex brush shapes Although each brush starts out as a six-sided cuboid, it doesn't have to stay that way. DarkRadiant offers several options for creating multi-sided brushes in more complex shapes. To create one of these shapes, first define a regular cuboid brush covering the volume you want the new shape to occupy, then choose the appropriate option from the *Brush* menu: [%autowidth] |=== |image:6Prism.png[]| *Prism* An n-sided approximation of a cylinder, with the axis of the cylinder aligned with the current 2D view. |image:6Cone.png[]| *Cone* A tapered n-sided cone, which always points upwards regardless of the 2D view axis. |image:6Sphere.png[]| *Sphere* A rotationally symmetric n-sided approximation of a sphere, with the axis of rotation pointing upwards. |=== While these shapes can be useful for certain architectural modelling, remember that brushes are always flat-shaded and are not generally a good substitute for spheres or cones created with patches or static meshes. [[CreatingARoom]] ==== Creating a room Although it is not too difficult to create a hollow room by creating floor, ceiling and wall brushes manually, this is a common enough operation that DarkRadiant provides a couple of shortcuts. These options can be found on the vertical toolbar at the far left of the main window. [cols="1,4"] |=== |image:CreateRoomBrush.png[width=320]| image:CreateRoom.png[width=36] *Create Room* Create a room whose interior size matches the size of the currently-selected brush. The wall thickness will be equal to the current grid size. |image:HollowBrush.png[width=320]| image:Hollow.png[width=36] *Hollow* Hollow out the selected brush, leaving the exterior dimensions the same. The wall thickness will be equal to the current grid size, but the wall brushes will overlap at the corners, rather than just touching each other as with *Create Room*. This is legacy tool from GtkRadiant, and generally inferior to *Create Room*. The overlapping wall brushes make it more difficult to precisely align interior textures, since part of the inner face is obscured (and therefore removed during map compilation). However, there may be occasional situations in which *Hollow* is useful, so it is retained in DarkRadiant. |=== The room creation tools do not require the initial brush to be rectangular -- you can quite happily *Create Room* with a triangular or trapezoidal brush, or a brush with sloping sides. However, with a more complex brush shape, the complexity of the resulting wall geometry increases considerably, so attempting to hollow out a 7-sided sphere is probably ill-advised. [[SplittingBrushes]] ==== Splitting brushes Sometimes it is necessary to divide a brush into two or more pieces, perhaps to create a doorway or other opening. The *Clipper* tool, accessed with the *X* key, is used for this purpose. .Splitting a brush into two parts image::ClipTool3D.png[align="center"] . Select the brush to be split (the Clipper can be activated with nothing selected, but it will not do anything useful). . Press *X* to activate the Clipper, or click on the respective icon on the left-hand editing toolbar. . Click in the 2D window at two different positions, to define the plane along which the brush will be split. The proposed split plane will be highlighted in blue; feel free to change 2D view axis with *Ctrl + TAB* or use the 3D camera view to better visualise the split plane. . Once the split plane is defined, press *Shift + Enter* to execute the split and keep _both_ halves of the brush; press *Enter* to execute the split and keep only one half. The part of the brush that is kept with *Enter* depends on the order in which you define the clip points: the points (marked *0* and *1*) will appear _clockwise_ on the brush edge according to the current 2D view. If in doubt, just use *Shift + Enter* to keep both parts, and delete the unwanted one afterwards. . Repeat the process to perform additional splits on the selected brush, or disable the Clipper with the *X* key. The Clipper is a toggled tool and will remain active until disabled. NOTE: It is possible to create _three_ split points before executing the split, which will define a split plane in three dimensions. Defining a three-point split plane which is actually useful, however, may be challenging. ==== Reshaping brush edges All brush edges can be moved independently, which gives you the ability to quickly create shapes like triangles or trapeziums. This functionality is accessed via the *Select Edges* tool on the upper toolbar, or with the *E* key. .Creating a trapezium using edge editing image::EdgeEditing.png[align="center"] . Select a brush. . Activate *Select Edges* with the toolbar button or *E* key. DarkRadiant will place a green control point at the center of each brush edge. . In either the 2D or the 3D view, click and drag on a control point to move its edge. The control point will turn blue and move along with the cursor. In the 2D view, dragging corners is generally easiest, since the resulting shape change can more easily be seen. . To reduce the number of brush sides, such as changing a rectangle into a triangle, simply drag one corner directly on top of another. The two edges will be merged. [[BrushBasedSelection]] ==== Brush-based selection As well as using brushes to define map geometry, you can also use them to select objects. There are three commands on the top toolbar which convert the selected brush(es) into a temporary selection volume: [cols="^1h,3h,10"] |=== |image:SelectCompleteTall.png[align="center",width=24]|Select complete tall| Select all objects that are _completely_ contained within the two-dimensional outline of the selected brush(es) in the current 2D view window, ignoring their position on the third axis (perpendicular to the screen). |image:SelectInside.png[align="center",width=24]|Select inside| Select all objects that are _completely_ contained within the selected brush volume(s) in all three dimensions. |image:SelectTouching.png[align="center",width=24]|Select touching| Select all objects that are touching the selected brushes. Unlike the previous two commands, this one does not remove the selected brushes, since it is designed to allow you to quickly select objects that are adjacent to real map geometry. |=== === Working with patches Patches are smooth-shaded Bezier surfaces that can be created and manipulated in the editor (unlike models), and used to represent a variety of curved shapes such as vaulted ceilings, arches or pillars. Patches are single-sided surfaces, not solid like brushes, and cannot be used to seal a map from the void -- any patch work on the boundary of a map will need solid brushes behind it to prevent the map from leaking. ==== Creating a simple patch A simple patch starts off as a flat rectangle, which can then be manipulated with vertex editing to produce a curved surface, if desired. To create a simple patch: . Set the 2D view axes (*Ctrl + TAB*) to define the orientation of the patch. The patch will be created facing directly towards the screen, so to create a horizontal (ceiling or floor) patch, the 2D view should be in XY (Top) orientation. . <> to define the width and height of the patch in the current 2D view (the third dimension is not important, since the patch will be infinitely thin once created). . With the brush selected, choose *Create Simple Patch Mesh* from the *Patch* menu. . In the dialog, choose the number of control points to define the shape of the patch along its width and height. A patch can have between 3 and 15 control points in each dimension; there will always be a control point at the extreme edge, and one in the middle. More control points allow more complex shapes but also require more manual adjustment -- creating a simple arch is much easier with just three control points. . Click *OK* to create the patch. .Simple patches with 3, 7 and 15 control points in both dimensions image::SimplePatchesControlPoints.png[align="center"] ==== Manipulating control points With a patch selected, press *V* to enter (or leave) vertex editing mode. This will display all of the control vertices, and allow you to select and move them. - *Left click* and drag a vertex to move just that one vertex. - *Shift + Left click* to add a vertex to the current selection set. When several vertices are selected, dragging any one of the selected vertices will move all of them together. - *Shift + Left drag* around several vertices to draw a selection rectangle that will toggle the selection state of all vertices inside it, selecting them if unselected and unselecting them if already selected. .Making an arch by raising the central row of vertices in a simple patch image::PatchVertexEditing.png[align="center"] ==== Adding or removing control points Control points can be added or removed from a patch using the appropriate sub-menus in the *Patch* menu. [cols="1h,3"] |=== |*Insert*| Add rows or columns of control points without changing the dimensions of the patch — the control points will become more densely packed. |*Extend*| Add rows or columns of control points while extending the patch dimensions. The existing control points are left in the same position. |*Delete*| Remove rows or columns without changing the dimensions of the patch (the opposite of *Insert*). The control points will become less densely packed. |=== .Inserting (top), Extending (middle) and Deleting (bottom) control points in a patch image::AddRemovePatchControlPoints.png[align="center"] ==== Thickening a patch When created, every patch has zero thickness and can only be viewed from one side; however, a patch can be made into an apparently solid object by creating additional patches automatically via the *Thicken* command in the *Patch* menu. .Thickening a patch (left) with side walls (center) and no side walls (right) image::PatchThicken.png[align="center"] The *Thicken* dialog presents several options: [cols="1h,3"] |=== |*Extrude along Vertex Normals*| Thicken the patch by extruding the patch surface in the direction it is facing. |*Extrude along X/Y/Z Axis*| Thicken the patch by extruding the surface along the specified axis, ignoring the face normal direction. |*Thickness (units)*| Distance in map units to extrude the patch by. |*Create seams ("side walls")*| If checked, the extruded patch will be made into a fully solid "object" with an interior volume completely enclosed by patches. If unchecked, only the initial patch and its extruded copy will be created, with the sides left open. |=== TIP: Although a thickened patch appears as a solid object, it still consists of individual patches which can be selected and manipulated individually. If you wish it to continue to behave as a solid, you can <> the patches together. ==== More complex patch shapes Just like with brushes, DarkRadiant offers several default patch shapes beyond the flat simple patch. These can be created by choosing the corresponding option in the *Patch* menu. There is no need to have a brush selected first in order to create these shapes, however if a brush _is_ selected, it will be removed and used to define the size of the patch shape. [cols="1,3"] |=== |image:PatchSphere.png[]| *Sphere* An approximation of a sphere (the quadratic Bezier patch implementation in Doom 3 and DarkRadiant does not permit the creation of a perfect sphere). |image:PatchCylinder.png[]| *Cylinder* A hollow cylinder aligned with the direction of the 2D view. |image:PatchCone.png[]| *Cone* A tapered cone pointing along the 2D view axis. |image:PatchEndCap.png[]| *End cap* An arch or half-cylinder covering a 180 degree angle, aligned with the 2D view axis. The peak of the arch will be at the top if created in front or side views, making this useful for curved ceilings and the like. |image:PatchBevel.png[]| *Bevel* Portion of an arch covering a 90 degree angle. This may be placed along room edges to give a curved appearance. |=== ==== Controlling patch subdivision Although patches are defined by Bezier curves, they are subdivided into flat polygons for rendering. By default, the number of polygons to create is determined dynamically by the game engine, based on the shape of the patch. However, you can also use the *Patch Inspector* to explicitly set the level of subdivision required, which can be useful when optimising a map by reducing on-screen polygon counts. .Default (automatic) subdivision, 2x2 subdivision, 3x3 subdivision, 3x10 subdivision image::PatchSubdivision.png[align="center"] To subdivide a patch: . Select *Patch Inspector* in the *View* menu to make the inspector widget visible. . With the patch selected, enable the *Fixed Subdivisions* checkbox. . Use the *Horizontal* and *Vertical* numeric spinboxes to set the number of polygons to divide the patch into. The value can range from *1*, making the patch completely flat regardless of control point positions, up to a maximum of *32*. Each dimension can have a different subdivision level, if required. === Applying textures When a brush or patch is created, it will be assigned a default texture. To apply a new texture, you must first select the brush, face or patch to be textured. There are two different selection commands: [cols="1h,3"] |=== |Shift + Left click| Select an entire brush or patch. Any chosen texture will apply to all faces. |Ctrl + Shift + Left click| Select a single brush face for texturing. This command is only available in the 3D camera view |=== Once you have selected the objects or faces to texture, you can use either the *Media* or the *Textures* tab to perform the texturing operation. [[MediaTab]] ==== The Media tab The *Media* tab shows a tree view which contains all of the textures available in the game installation. Selecting a texture in the tree will show a small preview swatch, along with some metadata about the texture definition. image::MediaTab.png[align="center"] To apply a texture to the selected brush, simply *Double-click* on a texture name in the tree. The tree view also offers a context menu with several options: [cols="1h,3"] |=== |Load in Textures view| Load all textures contained within the selected folder, making them available on the *Textures* tab. This option is not available when a single texture is highlighted. |Apply to selection| Apply the highlighted texture to the current object. This is identical to the *Double-click* operation, and is only available for single textures, not folders. |Show Shader Definition| Show a syntax-highlighted text window containing the definition of the selected texture. |Selected/deselect elements using this shader| Select or deselect objects in the map which the highlighted texture is applied to. This can be used for organisational purposes, or to identify whether a texture is used or not. |Add to/Remove from favourites| Add or remove the selected texture from the favourites list. The favourites list provides easy access to a user-chosen group of textures, and can be accessed by choosing the *Show Favourites* radio button at the top of the panel. |=== [[TexturesTab]] ==== The Textures tab The *Textures* tab provides a scrollable canvas containing preview swatches of all the textures which are currently loaded in the current map. image::TexturesTab.png[align="center"] When DarkRadiant first starts up no textures are loaded and this panel is empty. New textures can only be loaded via the *Media* tab (described in the <>), either by applying a texture directly to a brush, or by using the *Load in Textures view* command to explicitly load an entire folder of textures. Once textures are loaded onto the *Textures* tab, you can apply them to a selected object by *Left clicking* on them. By *Right clicking* on a texture you can access a context menu with a single command *Seek in Media browser*, which will highlight the clicked texture in the *Media* tab. [[SurfaceInspector]] ==== Using the Surface Inspector Once a texture is applied via the Media or Textures tabs, you will most likely wish to adjust the alignment and scale of the texture on the brush or patch face. DarkRadiant provides the *Surface Inspector* for this purpose, which can be toggled with the *S* key or by choosing the option in the *View* menu. image::SurfaceInspector.png[align="center"] The Surface Inspector can be used to adjust textures on a single brush or patch face, or several selected faces/brushes/patches at once. If more than one face is selected and these faces have different values for text boxes in the dialog, the text box will be greyed out, however it is still possible to use the buttons to make changes which will be applied uniformly to all selected faces. [cols="1h,3"] |=== |Shader|This shows the full name of the texture applied to the selected face(s). You can use the tree button to bring up a new dialog which allows you to choose a new texture. |X/Y Shift|These text boxes show the current texture shift (translation) on the horizontal and vertical axes. The associated arrow buttons will increase or decrease the texture shift by the current *Step* value. |X/Y Scale|These show the current texture scale in the horizontal and vertical directions. The arrow buttons will increase or decrease the scale by the current *Step* value. |Rotation|Shows the current texture rotation, in degrees. The arrow buttons will rotate the texture clockwise or anticlockwise by the current *Step* value. |Fit|These controls allow you to fit an exact number of copies of the texture across the face, so that the texture edges correspond to the face edges. The numeric spin boxes control how many copies of the texture are tiled on each axis. You can enter a value manually (including fractional values above or below 1.0) or use the spin buttons to quickly increase or decrease the number of tiles. Using the spin buttons will apply the fit immediately, so you can quickly preview the results in the camera view. Toggle the image:preserveAspect.png[] button to *preserve aspect ratio* when using the spin buttons to fit the texture on one axis. This automatically adjusts the other axis so that the aspect ratio of the texture image is preserved, ignoring the value in the other axis' spin box. This can be useful for textures like wooden planks, where you might want an exact number of plank _widths_ on a certain brush face but the number of _lengths_ is not important (since the texture is seamless); in this case, avoiding aspect ratio distortion is more useful than fitting an exact number of lengths. | image:align_top.png[]  image:align_bottom.png[]  image:align_left.png[]  image:align_right.png[] |These buttons shift the texture so that the Top/Bottom/Left/Right edge of the face are aligned with a texture boundary, but otherwise do not modify the scaling of the texture (unlike the *Fit* operation). | image:flip_horiz.png[] image:flip_vert.png[] |Flips (mirrors) the texture along the horizontal or vertical axis. |Natural|This button resets the texture to a default alignment and scale, based the location and size of the face. The adjacent *Scale* spinbox allows you to control the default scale used for *Natural* fitting. |image:texture_lock.png[] |If this is enabled, the alignment of the texture will be preserved relative to the face if the brush or patch is moved in 3D space. If disabled, the texture itself will remain fixed in 3D space as the brush or patch moves, resulting in the alignment changing. Typically, if you have *Fit* a particular number of texture tiles across a face, you will want to preserve alignment with *Texture Lock*. Conversely, if the texture is applied to a much larger group of brushes with a common texture (that needs to align across all of the brushes, regardless of how they are moved or resized), you will want to disable *Texture Lock*. |=== [[ShaderClipboard]] ==== Using the shader clipboard While constructing a map it will frequently be necessary to apply the same texture to several different surfaces such that they appear seamless in game. In order to assist with this, DarkRadiant provides a *shader clipboard* which allows shaders to be copied and pasted between primitives, and is independent of the main clipboard used for copying and pasting other objects. ===== Copying a shader There are two ways to copy a shader to the shader clipboard. 1. Select a _single face_ (not an entire brush) with *Ctrl + Shift + Left click* in the 3D view, then choose *Edit -> Copy shader*. 2. Directly *Middle click* the face in the 3D view (there is no need to select it first). In both cases, the *ShaderClipboard* section of the bottom status bar will update to show the new value of the shader clipboard. If the *Media* or *Textures* tab is visible, their contents will also update to view the selected shader. NOTE: Selecting a texture explicitly in the *Media* or *Textures* tabs will also update the shader clipboard with the selected shader. ===== Pasting a shader Once a shader is on the shader clipboard, it can be pasted onto another surface in a number of ways: 1. Select the destination face with *Ctrl + Shift + Left click*, then choose *Edit -> Paste shader* or *Edit -> Paste shader (natural)*. 2. Directly *Middle click* the destination face while holding down either *Ctrl* (to paste the shader with projected coordinates) or *Shift* (to paste the shader with natural coordinates). .Natural or projected pasting **** The difference between natural and projected coordinates is apparent when pasting a shader onto a curved patch. With *projected* coordinates (*Ctrl + Middle click*) the texture on the patch will be aligned identically to the texture on the source face, which might result in a stretched texture depending on the angle between the patch and the source face. With *natural* coordinates (*Shift + Middle click*) the texture will flow over the curved surface in a more natural manner. When pasting a shader onto a flat brush face, there may be little or no difference between the two options. **** === Working with entities If brushes are the bricks and mortar of a map (often literally), entities are its fixtures and fittings. Every object in a map which "does something" other than form part of the level geometry is an entity: lights, audio speakers, particle emitters, static meshes, animated creatures or machinery. There are also various functional entity types which provide vital metadata to the game engine, such as determining where the player should start, or how creatures should navigate between locations. DarkRadiant provides certain common functionality to all entities, such as the ability to edit properties using the *Entity* tab. Particular entity types are sufficiently common, however, that they have their own dedicated creation and editing tools. *Light*:: Every map requires at least one light source in order to render anything in game. A light occupies a rectangular volume, which can be created and resized much like a brush, and has properties to determine its colour, visible shape and falloff pattern in three dimensions. Lights can optionally cast shadows, and can even be animated to flicker or flash. *Model (func_static)*:: Model entities represent geometry that is not compiled as part of the map itself. The model geometry can either be derived from brushes and patches created inside DarkRadiant, or from an external model file in ASE or LWO format. Model files are the primary mechanism for including fine detail in a map which would be cumbersome to create with brushes and patches. *Speaker*:: Essentially the audio equivalent of a light, a speaker entity represents the point from which an in-game sound source will emanate. It has properties to control its size and falloff, and optionally override certain properties of the sound shader itself, such as volume. *Player start (info_player_start)*:: This entity tells the game engine where to place the player when a map is first loaded. A map without such an entity will not be playable. [[CreatingLights]] ==== Creating lights To create a light, *Right click* in the 2D view and choose *Create light…*. The position and size of the light volume depends on the current selection: - If _nothing_ is selected, then a light volume will be created at the clicked position with a default size. - If a _single brush_ is selected, the brush will be deleted and the light volume will match the size and position of the brush. - If _several brushes_ are selected, then all selected brushes will be deleted and the light volume will be sized according to the bounding box of the brushes (i.e. the smallest box that would contain all of the brushes). Unselected lights are shown in the 2D view as small boxes, while selected lights also show the boundaries of the light volume. .Light entity selected (left) and unselected (right) image::LightSelectedAndUnselected.png[align="center"] A selected light entity can be moved by dragging inside the small center box, and it can be resized by dragging outside the edge of the light volume. Unlike brushes, light volumes will by default resize symmetrically, so that the center point does not move during the resize. NOTE: Although light volumes can be resized like brushes, their shape can never be changed; every light is an axis-aligned cuboid. This does not, however, mean that they need to _look_ rectangular in game. See the <> for details on how to change the falloff texture using the light inspector. There are a couple of options on the top toolbar which control the display and behaviour of light volumes: [cols="^1h,3h,10"] |=== |image:view_show_lightradii.png[align="center",width=24]|Show all light volumes| If enabled, light volume boundaries will be rendered in the 2D view for _all_ light entities, not just selected entities. The default behaviour is to show only the center box for unselected light entities. |image:dragresize_symm.png[align="center",width=24]|Drag-resize entities symmetrically| If enabled (the default), light entities will be resized symmetrically, without moving the center point. If disabled, lights will be resized like brushes: dragging an edge will move only that edge, while the opposite edge remains fixed. |=== [[LightInspector]] ===== The light inspector When initially created, a light is pure white in colour and has an unrealistic rectangular illumination pattern matching its shape. You can change these properties using the light inspector, which is accessed with the *L* key. image::LightInspector.png[align="center"] TIP: The light inspector can change the properties of a single light, or multiple selected lights simultaneously. *Light volume (omni vs projected)*:: The majority of lights in a map will be the default, omnidirectional shape. An omni light is a simple cuboid which emits light in all directions from its center to its edges. + A projected light is pyramid-shaped, and emits light from the tip of the pyramid towards the base. Projected lights behave more like spotlights in real-life, and can be used to highlight particular areas or project images of windows onto the floor. *Colour*:: Use the colour selector button to display a standard colour selection dialog. As well as changing the hue, the light colour also governs the overall brightness of the light. You can use the slider below the colour button to adjust the brightness of the selected light(s) without changing the hue, with realtime feedback displayed in the 3D camera view if lighting preview mode is enabled. *Texture*:: The falloff texture controls the shape of the lit area when rendered in-game; the square texture chosen here will be mapped directly onto the rectangular shape of the light volume. Light textures can be simple, such as the generic circular gradient of `biground1`, or much more complex, including multiple colours or animation. *Options*:: There are a few light-propagation options which are mostly used to tweak performance. In particular, disabling shadows for any light which does not actually _need_ to cast shadows can give a significant boost to rendering speed. [[CreatingModels]] ==== Creating models Static models can be used to provide fine details in a map which would be difficult or impossible to create in the editor with brushes or patches. Models are created with an external 3D application such as Blender, Lightwave or Maya, and saved into the game asset tree in LWO or ASE format. To insert a model, ensure that nothing is selected, then *Right click* in the 2D view and choose *Create model…*. DarkRadiant will show the model selector dialog: image::ModelSelector.png[align="center"] In the top-left of the model selector window is a tree of all available models in the game installation. Models may have different _skins_, which are variants of the same model with different textures applied. If a model has skins available, these will be listed as children of the model entry in the tree. Choosing a model or one of its skins will show a preview render in the large widget on the right-hand side. Various metadata such as the polygon count and the applied textures are also shown in table at the lower left. When you have chosen the desired model, click *OK* to insert it into the map. The model will be inserted at the position where you originally right-clicked to show the model chooser. ==== Creating a player start marker The game requires a special entity (`info_player_start`) to mark the position at which the player should enter the map. Without such an entity the map will be unplayable. To create this entity, ensure that nothing is selected then *Right click* in the 2D view and choose *Create player start here*. DarkRadiant will create the player start entity at the clicked position. Since it makes no sense to have more than one player start location, DarkRadiant will not enable the *Create player start here* menu option if there is already an `info_player_start` in the map. Instead, you may choose *Move player start here* to move the existing entity to the clicked position. ==== Creating other entity types Entity types without a dedicated item in the right-click menu are created using the generic *Create entity…* option, which displays a dialog very similar to the <>: image::EntityClassSelector.png[align="center"] Just like the model selector, the entity selector displays a tree of all available entity types in the game installation, and a large preview widget which shows an approximate rendering of the entity, if appropriate. Purely functional entity types such as `info_location` or `info_player_start` do not have any visible appearance and their render preview will be blank. Some entity types have a short textual description giving information about their usage; if present, this is displayed in the text box underneath the entity class tree. After selecting the desired entity type in the tree, click the *Add* button to insert an instance of the entity into the map at the right-clicked location. If the selected entity type requires a brush selection and no brush is selected, a warning will be shown at this point. [[EntityInspector]] ==== Editing entity properties Every entity has a list of key/value pairs known as _properties_ or _spawnargs_. These properties are displayed on the *Entity* tab of the editing panel. image::EntityInspector.png[align="center"] The entity panel lists all of the properties of the currently-selected entity, showing each property's name, its current value, and an icon representing its type (boolean, vector, text etc) if known. Selecting a property will populate the two text boxes in the center of the widget with the property name and value, allowing the value to be edited. If the selected property is of a known type, the panel at the bottom will show a custom widget appropriate for editing the particular property, e.g. three separate numeric spinboxes for a vector property, a colour selector widget for a colour property, and so on. *Changing a property value*:: To change the value of the selected property, simply enter the new value in the lower text box, then hit *Enter* or click the green tick button. If the property has a type-specific editing widget, you can also change its value using the controls in this widget. *Adding a new property*:: There are two different ways to add a new property: . Enter a new property name in the upper text box (which shows the selected property name), and hit *Enter*. This does not rename the selected property, but adds a new property with the edited name and the current value. . *Right click* in the list of properties and choose *Add property* from the context menu. This will display a new dialog listing all known properties along with their descriptive text (if available). Selecting a property in this dialog and choosing *OK* will add the property to the entity with a default value of "-", which can then be edited in the entity panel itself. *Deleting a property*:: To delete the selected property, *Right click* on the property in the list and choose *Delete property*. The entity panel provides two options controlling its behaviour: [cols="1h,3"] |=== |Show inherited properties|If checked, all properties that apply to the selected entity will be shown, including those which are inherited from the entity type declaration in the game installation. If unchecked, only those properties explicitly set on this particular entity (and stored in the map file) will be shown. You can change the value of an inherited property by selecting it and entering a new value in the entity panel; this will create a new explicit property on the entity which overrides the inherited default. |Show help|Enables or disables the text widget at the bottom of the panel which shows a brief explanation of certain properties. If a property has help text available, the question mark icon will be shown in the *?* column. |=== [[ReparentingPrimitives]] === Reparenting primitives Whenever a new brush or patch is created, it will automatically be made a child of the special *worldspawn* entity, which serves as the default entity containing all of the primitives which define the world geometry. However, *worldspawn* is not the only entity which can contain brushes and patches as children. When you create a model using the <>, DarkRadiant will insert a type of entity called a *func_static* into the map to represent the model geometry. A *func_static* can contain a model file loaded from disk in LWO or ASE format, but it can also be used as a parent for one or more primitives created within DarkRadiant. In either case, the behaviour of *func_static* is the same: it represents a static mesh which is rendered in game but is considered separate from the main world geometry, meaning that it does not participate in map compilation, will not seal the map from leaks, and will not cause intersecting brushes to be subdivided. It is therefore often useful to make certain brushes and patches — typically those which represent "fine detail" rather than entire walls, floors and the like — into *func_static* entities to improve in-game performance and reduce the chances for map compilation problems caused by excessively complex world geometry. The *func_static* entity class is not the only type of entity which can contain primitives: there are several other *func_* entities which perform various functions, for example *func_rotating* which allows geometry to rotate continuously. DarkRadiant offers dedicated commands to convert to/from a *func_static* since this is a very common operation, however the ability to <>, <> individual primitives behaves the same for all types of primitive-containing entity. ==== Converting primitives into func_static To convert one or more existing primitives into a *func_static* entity, simply select all of the primitives, right-click in the 2D window, and choose *Convert to func_static*. [[SelectChildPrimitives]] ==== Manipulating individual child primitives After converting a primitive, a number of changes are noticeable: . The primitive may be drawn in a different colour. . The primitive will no longer be resizeable by dragging its boundary with the mouse. . When the primitive is selected, the *Entity Inspector* will no longer show the *worldspawn* entity, but a new entity with a different *classname* (e.g. `func_static`). You can set spawnargs on this entity like any other (including giving it a custom name). . Selecting any contained primitive will cause a small X/Y/Z axis widget to be drawn at the entity's origin position (which may be inside one of the primitives, or outside all of them, depending on their layout). . If there are multiple primitives contained within a single entity, selecting any individual primitive will cause all of the entity's primitives to be selected. This allows you to easily move the entire static object by simply dragging any one of its primitives. However, it is still possible to perform operations on a single primitive, for example resizing a brush, by selecting it with the *TAB* key. Each press of *TAB* will cause DarkRadiant to select a different primitive contained within the entity, after which it will return to selecting the entire entity. With only a single primitive selected, all of the normal operations are possible on that primitive, for example deleting or resizing it. The <> widget makes it clear whether you have selected an entity or a primitive within that entity, using the text above the list of entity properties. If an entire entity is selected, the text will appear similar to `Entity 1`, whereas with a primitive selected it will read `Entity 1, Primitive 1`. [[AddRemoveChildPrimitives]] ==== Adding or removing primitives Once you have created a *func_static* or similar entity from a number of primitives, you can add or remove primitives without needing to create a new entity from scratch. *Adding a primitive*:: Select the entity, then expand the selection (i.e. using *Shift + Left click*) to include one or more existing primitives to add to this entity. Then choose *Edit -> Reparent primitives*. *Removing a primitive*:: Use the *TAB* key to select the individual primitive to remove (you must do this even if there is only one primitive in the entity), then choose *Edit -> Reparent primitives to worldspawn*. The removed primitive will still exist in the map but it will be a regular worldspawn brush or patch, not parented to any other entity. *Unparenting all primitives*:: With the entity selected, simply right-click in the 2D view and choose *Revert to worldspawn* to turn all of the primitives back into worldspawn. === Compiling a map DarkRadiant does not include functionality for compiling a map into the form needed by the game engine; instead, you must use external tools or the map compiler built into the game itself. For Doom 3 and the Dark Mod, the following commands are used within the in-game console (which can normally be accessed with the key immediately above `TAB`): [horizontal] `dmap `:: Compile the map called `mymapname.map`, which must be located within the `maps` directory of the mod installation. If there are any problems compiling the map (e.g. a leak), the error will be displayed in the console output. `map `:: Load the compiled map `mymapname.map` into the game engine and start playing it immediately. TIP: When compiling and testing maps, it may be helpful to set your game to play in windowed mode, with a reduced resolution. This will allow both the game and DarkRadiant to be visible on the screen as separate windows, which you can easily switch between during the compile and test cycle. ==== Preventing leaks A map "leak" occurs when the play area is not fully enclosed with a complete shell of opaque brushes. If the map leaks, compilation will fail and the map will not be playable. In order to minimise the likelihood of a map leak, ensure that your map has all of the following properties: - The map interior is _completely_ sealed from the exterior void by brushes (not patches). It is much easier to achieve this by building up a map carefully, making good use of the grid snapping functionality, rather than haphazardly throwing brushes together and hoping to seal them later. - All of the sealing brushes have an opaque texture. Skybox textures are considered opaque and are OK, however semi-transparent or perforated mesh textures are not. - The origin point of _every_ entity in the map lies within the sealed map interior. It is OK if a large model extends outside of the map, provided that its origin point is on the inside. WARNING: Do *not* be tempted to avoid leaks by enclosing your entire map in a single huge box. This may seem to solve the problem (the map will indeed not leak), but it completely negates the important performance optimisations that the map compiler carries out when it "flood fills" the map interior. [[PointFile]] ==== Locating leaks with a pointfile No matter how hard you try to avoid leaks, occasionally they will happen. In this case the *pointfile* functionality is helpful to identify the location of the leak. After the map compilation has failed with a leak, return to DarkRadiant and choose *Pointfile* from the *File* menu. This will automatically load the point file associated with the current map, which contains a series of points identifying the path to the leak. This path will be rendered as a bright red line in both the 2D and 3D views: .A pointfile rendered in both 3D and 3D views image::Pointfile.png[align="center"] In this example we can clearly see that the map has leaked because the far wall brush does not join up with the ceiling. == Organising a map Since a fully developed Dark Mod map is large and complex, DarkRadiant provides several tools to make organising a large map easier. Objects can be grouped, sorted into user-defined layers and filtered using various criteria, while the prefab system allows large chunks of map to be reused or shared with other mappers. [[Group]] === Grouping objects DarkRadiant allows a number of objects to be grouped together, so that they can be selected and manipulated as a single unit. To *create* a group: . Select several objects. . *Right-click* in the 2D window to show the context menu. . Choose *Group Selection*. Once the objects are in a group, selecting any object in the group will automatically select all other objects in the same group. To *remove* a group, select the group then choose *Ungroup Selection* from the 2D view context menu. NOTE: Groups can be nested, by creating a group that includes one or more existing groups. When you ungroup such a nested group, the original component groups will be restored. [[WorkingWithPrefabs]] === Working with prefabs DarkRadiant allows a collection of objects to be saved to disk as a *prefab*, which can then be imported into other maps. You can use prefabs to store anything from a single small object to a vast section of map geometry complete with lights and AI. ==== Exporting to a prefab . Select the objects in the map that you wish to include in the prefab. . From the *File* menu, choose *Save selected as prefab...* . Use the file chooser dialog to choose a location and name for the prefab file. TIP: Unlike actual `.map` files which must be accessible by the game engine, prefabs are a DarkRadiant-only feature that have no significance to the engine. You are therefore free to store prefab files wherever you wish, either inside or outside the game installation directory. [[ImportPrefab]] ==== Importing a prefab Either right-click in the 2D window and choose *Insert prefab...*, or open the *File* menu and choose *Import prefab...*. This will show the prefab browser. image::PrefabChooser.png[align="center"] Like the model selector, the prefab selector shows a tree of available prefabs on the left, and a preview window on the right giving an idea of what the prefab looks like. Using the radio buttons at the top of the window, you can choose whether to browse prefabs contained within the game installation, or within a custom directory of your choice. The preview window functions much like the 3D view in the main application: *right click* to enter or leave camera mode, which enables the following motion commands: [cols="1h,3"] |=== |Mouse move|Change the camera view direction (pan or tilt) |Mouse wheel|Zoom the camera |Up/Down arrow|Move the camera forwards or backwards |Left/Right arrow|Move the camera left or right |=== When you have chosen the desired prefab, click *OK* to insert it into the map. Before inserting the prefab, you can use the *Create Group out of Prefab parts* checkbox to control whether the prefab is automatically grouped as a single object, or inserted as separate selectable objects. === Exporting models DarkRadiant provides a limited ability to export scene geometry into a number of 3D model file formats: ASCII Scene Export (ASE), Lightwave (LWO) or Wavefront OBJ. This functionality is provided to help with organising frequently-used map elements — DarkRadiant is not intended to compete with full-featured 3D modelling applications such as Blender or 3DS Max. Exporting to a model is similar to exporting to a prefab, except that models can only contain geometry (brushes or patches), not other map entities such as lights or speakers. However, unlike prefabs, models can be edited with other 3D software, and exporting map geometry as a model might provide a useful template for creating map-specific static meshes in a more powerful modelling tool. To export a model: . Select the geometry to be exported. Note that DarkRadiant currently does not complain if you select non-geometry such as lights, however these will not appear in the resulting model file. . Open the *File* menu and choose *Export selected as model...* . In the *Output Format* dropdown, choose one of the supported model formats: `ASCII Scene Export (.ase)`, `Lightwave Object File (.lwo)`, or `Wavefront OBJ (.obj)`. . Choose the path for the exported model file in the *File Path* entry box. . Click *OK* to export the model. === Using layers When a map contains a large number of objects, it may become difficult to work with the 2D views as a result of the visual clutter. Organising the map into several *layers* can help solve this problem. The visibility of each layer can toggled independently, allowing you to focus on the objects you want to work with. Layers do not impose any requirements on the physical layout of objects: it is possible to include objects spread all over a map into a single layer. For example, you can have a layer for all enemies, another layer for all lights, another layer for brushwork, and so on. ==== The Layers window To show or hide the *Layers* window, choose `Layers` from the `Edit` menu. The window lists all of the layers which exist in the current project, and allows you to perform various operations on them. image::LayersWindow.png[align="center"] *Creating a layer*:: To create a new layer, click the `New` button at the bottom of the window. A popup will be shown asking for the name of the new layer. Once the layer is created, it will appear in the list. *Deleting a layer*:: Click the red 'X' button to the right of a layer to delete it. Deleting a layer does *not* delete the objects in the layer, only the layer itself. Any objects in that layer will be moved to the default layer. *Renaming a layer*:: Click the edit button to the right of a layer name to change the name. A popup will be shown asking for the new name. *Selecting objects on a layer*:: Click on the name of a layer itself to select all objects on that layer. *Toggling visibility*:: The button to the left of a layer name is used to toggle the visibility of objects on that layer. If objects are visible, a tick is shown in the button, otherwise it is empty. *Changing the active layer*:: The visibility toggle button shows a star for the layer which is currently set as the active layer. To change the active layer, *Ctrl + Left click* on the layer you wish to set as the new active layer. ==== Moving objects into layers An object can be placed in any number of layers. To see which layers a selected object is in, look at the narrow coloured rectangle next to the layer name in the *Layers* window. The rectangle will turn from grey to pink for each layer that contains the selected object. .A light in two layers: "Default" and "Lights" image::LightInTwoLayers.png[align="center"] All newly-created objects will be placed in the *Default* layer. You can move or copy objects between layers using the options in the 2D view's context menu. *Create layer...*:: Bring up the name entry dialog and create a new layer, exactly as if the *New* button in the *Layers* window had been clicked. *Add to layer...*:: Copy the selected object into the chosen layer, without removing it from its existing layer(s). *Move to layer...*:: Move the selected object into the chosen layer, removing it from all other layers. *Remove from layer...*:: Remove the selected object from the chosen layer. === Filtering map elements While the Layers feature allows maps to be organised into manual groupings of objects, DarkRadiant also provides a mechanism for controlling the visibility of items based on their characteristics. This is controlled via the *Filter* menu. ==== Built-in filters The *Filter* menu is populated with a number of built-in filter rules which are expected to be useful to mappers. Each filter may be activated independently, and each activated filter will be shown with a tick alongside its name. Filters operate in a "subtractive" sense: if a filter is active, objects matched by that filter will be hidden; the remaining visible objects will be those which are not matched by any active filters. TIP: Active filters are persisted into settings, and are therefore retained between DarkRadiant sessions. The built-in filters include: [cols="1h,3"] |=== |All entities|Hide all entities other than the worldspawn, leaving only brushes and patches visible. |World geometry|The inverse of *All entities*. Hides brushes and patches while leaving entities visible. |Brushes|Hide only brushes, leaving patches and entities visible. |Patches|Hide only patches, leaving brushes and entities visible. |Caulk|Hide any brush or patch which has the *caulk* texture applied to at least one surface. |Collision surfaces|Hide the additional collision meshes which are embedded in certain models, while leaving the models themselves visible. This filter is especially useful because collision meshes often obscure parts of the model itself. |=== Aside from the list of filters, the *Filter* menu contains three other options: [cols="1h,3"] |=== |Activate all filters|Activate every filter in the list. Very unlikely to be useful, because it will probably result in every object in the map becoming invisible. |Deactivate all filters|Turn off all active filters. This one _is_ useful, since you may have manually activated a number of filters and want to turn them all off at once. |Edit filters...|Display a dialog allowing you to create, edit and manage the list of available filters. |=== ==== Customising filters In addition to the filters supplied with the mod distribution, DarkRadiant also allows you to add your own custom filters to the list by choosing the *Edit Filters...* menu option. This displays a dialog containing the list of all available filters, including built-in ones. Use the *Add* and *Delete* buttons to add or remove custom filters from the list, and the *Edit* button to enter a new dialog which allows you to edit the rules of the selected filter. Built-in filters cannot be removed or edited, but you can choose the *View* button to open the filter editor in a read-only mode. .The filter editor dialog image::FilterEditor.png[align="center"] Each filter consists of a number of *rules*, which are applied in the order shown in the list box. Filters may contain only a single rule ("hide all speaker entities"), or multiple rules ("hide all entities, then show only speaker entities"). You can freely add, remove or reorder rules using the buttons to the right of the rules list. Each rule has the following components: *Index*:: An integer representing the rule's position in the list, numbered from zero. *Type*:: This controls what the rule is "looking for" when it tries to match objects to hide or show. Currently there are four rule types: *entityclass* which matches the classname of entities (e.g. "speaker"), *object* which matches either "brush" or "patch" and is used for controlling the visibility of map geometry, *texture* which matches the name of an applied texture, and *entitykeyvalue* which matches the value of a specific property on the entity. *Entity Key*:: This column is only used for *entitykeyvalue* rules, in which case it contains the name of the property to match (while the _value_ to match will be contained in the *Match* column). *Match*:: This contains the actual value to be matched by the rule. Its interpretation and allowed values will depend on the rule type. For *object* type rules the value must be "brush" or "patch", whereas with all other rule types the value may be any arbitrary string. *Action*:: Choose whether this rule will result in matched objects being shown, or hidden. The filter system starts with everything being visible by default, so a filter which does not contain at least one *hide* rule will have no effect. === The entity list As a map becomes larger and more complex, keeping track of its contents may become more challenging. To assist with this, DarkRadiant provides an *Entity List* which functions as an "outline" view of the map, listing all entities and their child brushes and patches (if any). The entity list can be accessed by choosing the *Entity List* option from the *View* menu. .The entity list, showing a number of entities in a small test map image::EntityList.png[align="center"] The tree structure shown in the entity list corresponds to the structure of the map itself: a single "world" entity which acts as the parent of the brushes and patches in the map, alongside a number of other entities that have been placed by the mapper, some of which may contain their own child brushes or patches. Clicking on an entity in the list will cause it to be selected in the map. If the *Focus camera on selected entity* checkbox is enabled, the camera will additionally be moved to view the clicked entity. By enabling the *List visible nodes only* checkbox, you can limit the entity list to show only entities which are not currently hidden via filters. == Dark Mod features The Dark Mod is a considerably more complex game than vanilla Doom 3, and its maps therefore include certain settings and features that would be cumbersome to configure manually by entering property values on entities. DarkRadiant therefore provides a number of Dark Mod specific dialogs which are described in this section. NOTE: Most Dark Mod features are compiled as separate plugins, and may not be built by default on certain platforms. If these features seem to be missing, contact the distributor of your DarkRadiant binary package for advice, or examine the build options if you are compiling DarkRadiant yourself from source code. === The Difficulty editor Most Dark Mod maps can be played on one of three possible difficulty settings, typically named "Easy", "Medium" and "Difficult" (although these names can be overridden). The precise effects of each of these difficulty settings are fully under the control of the map author, and might include such effects as spawning or despawning particular enemies, changing enemy health or patrol routes, or modifying the details of objectives. DarkRadiant provides a Difficulty editor dialog to facilitate one particular class of difficulty-dependent modification: making global changes to entity classes throughout the map. This could be used, for example, to change the health of every instance of a particular enemy, or (as shown in the diagram) removing a particular enemy type's ability to relight torches. .The Difficulty editor, showing a modified property on a particular entity class image::DifficultyEditor.png[align="center"] The Difficulty editor shows the names of the available difficulty levels in a dropdown widget, beneath which are the settings for the selected difficulty level. The difficulty names are customisable on a per-map basis — normally these will be the default values of "Easy", "Medium" and "Difficult", but if the current map has customised difficulty names DarkRadiant will adjust the tab names accordingly. On the left is a tree view showing all of the property overrides for the current difficulty level. Each top-level item is a particular entity class, which contains all of the property changes that are made to this entity class in this difficulty level. In this example, the `ai_builder_guard` entity has its `canLightTorches` property set to 0 on the Easy difficulty setting, meaning that all enemies of this particular type will not be able to relight torches. *Adding a setting*:: To add a new property setting for the current difficulty level, click the *Add* button. The widgets on the right hand side will become available, allowing you to choose an entity class, a property ("Spawnarg") to change, and the change to make ("Argument"). You can choose a number of mathematical operations for the modification, including a simple value assignment, or an addition or multiplication. After specifying the values, make sure you click the *Save* button to commit the changes into the list view. *Removing a setting*:: Select an item in the list view and click the *Delete* button to remove a particular setting. You can only remove individual assignments from the list; to remove all of the assignments for a particular entity class, you must select and delete each one individually. *Editing the difficulty name*:: To edit the name of the current difficulty level, click the edit button to the right of the dropdown, and enter a new name in the text box. The modified name will be written into a property on the `worldspawn` entity and reflected both in game and in DarkRadiant. TIP: For details of more advanced difficulty-dependent changes, such as modifying the behaviour of a *single* entity (rather than an entire entity class), consult the Dark Mod Wiki. === Game Connection The Dark Mod includes functionality to dynamically interact with a DarkRadiant session running on the same machine, allowing certain information (such as camera position) to be synchronised both to and from the game, and for certain entity property changes to be pushed to the running game without needing to restart. These features are accessed in DarkRadiant through the *Connection* menu and buttons on the camera view toolbar. ==== Activating the connection . In *The Dark Mod*, load the map which you are currently editing in DarkRadiant. . Bring down the game console and enter the command [listing] com_automation 1 + This should result in a status message indicating that the game is listening for connections on a particular network port. [listing] Automation now listens on port 3879 The game process is now ready to exchange data with DarkRadiant. ==== Synchronising camera position You can synchronise the DarkRadiant camera position and the game player position in both directions: editor to game and game to editor. This feature is most easily controlled with the buttons on the camera view toolbar, but it can also be activated from the *Connection* menu. [cols="^1h,3h,10"] |=== |image:CameraSync.png[align="center",width=24] |Game position follows DarkRadiant camera| Any motion of the DarkRadiant camera will be transmitted in realtime to the game, resulting in the player position moving (in *noclip* mode) to the same position and view direction. This is a toggled option which remains active until switched off. |image:CameraSyncBack.png[align="center",width=24] |Move camera to current game position| Update the DarkRadiant camera to match the current player position and view direction in game. This is a single-shot command; there is no mechanism to continuously move the DarkRadiant camera in response to player motion in game. |=== == Command reference === File menu *New map*:: Prompt to save and close the current map (if necessary), then start working on a new empty map. *Open map...*:: Prompt to save and close the current map (if necessary), then display a file browser to choose and load an existing map file from disk. *Import map...*:: Display a file browser to choose and load an existing map file from disk, merging the contents with the existing map *Import prefab...*:: Display the <> to choose and import a prefab from disk. NOTE: Importing a map and importing a prefab are functionally identical operations; the only difference is the user interface used for choosing what to import. The prefab browser is designed to offer a user-friendly workflow for browsing, previewing and importing from a library of frequently-used map elements, while *Import map* may be more useful for merging two or more partially-complete maps. *Save*:: Save the current map to disk under its existing file name. *Save as...*:: Display a file browser to choose a new name for the current map, then save to this new file name in future. *Save copy as...*:: Display a file browser to choose a new filename to save this map into, without changing the current map name for future *Save* operations. *Save selected as Map...*:: Choose a file name and save the currently-selected items into a new map file without changing the current map name. Equivalent to *Save copy as* but it only saves the selected items, not the entire map. *Save selected as prefab...*:: Equivalent to *Save selected as Map* but it saves the selected items into a <> (`*.pfb`) file in the standard prefab location. *Save selected as Collision Model...*:: Allows a selected map object (typically a brush) to be set as the collision model for a particular ASE or LWO model. After choosing this option, DarkRadiant will display the model chooser dialog, allowing you to choose the particular model that the selected object should be associated with. The selected brush is then saved, and associated with the model so that subsequent insertions of the same model will use the new collision geometry. *Reload Models/Selected Models/Skins/Scripts/Readable Guis/Materials/Defs/Particles*:: Forces DarkRadiant to re-read the selected category of items from disk, refreshing its internal data structures. This is necessary if you have edited or re-exported some asset which DarkRadiant is using in the current map and you want to see the latest changes. *Game/Project Setup...*:: Show the <> dialog for configuring game-specific settings. *Pointfile*:: Load and show the <> for the current map, if there is one. If more than pointfile is available, a dialog will be shown allowing you to choose which pointfile to load. An error dialog will be displayed if there is no current pointfile (which is usually the case if the current map has not leaked during compilation). Choose this option a second time to hide the rendered pointfile. *Exit*:: Exit DarkRadiant, prompting to save the current map if necessary. === Edit menu *Undo*:: Undo the most recent operation. *Redo*:: Redo the most recently undone operation. *Copy*:: Copy the selected item(s) to the clipboard. *Paste*:: Paste the item(s) on the clipboard to their original world location. NOTE: Objects copied to the clipboard are represented using the same text format which can be found in `.map` files. This makes it possible to save clipboard content into a file and load it later as an actual map fragment. *Paste to camera*:: Paste the item(s) on the clipboard to the current camera location, ignoring their original world location. *Duplicate*:: Make a copy of the currently selected item(s), slightly offset from their original position. *Delete*:: Remove the currently selected item(s). *Group selection*:: Combine the selected items into a <>. *Ungroup selection*:: Split the selected group back into individual objects. *Reparent primitives*:: Make all selected worldspawn brushes or patches into children of the selected func_static (or similar entity). Requires exactly one entity to be selected, along with at least one primitive which is currently a child of the worldspawn. *Reparent primitives to worldspawn*:: Unparent the selected primitive from a func_static (or similar entity), making it a child of the worldspawn. Before using this command you must first select a single primitive with the *TAB* key (even if the entity only contains a single primitive), otherwise the whole entity will be selected and the command will silently fail. TIP: To unparent *all* of an entity's primitives and convert them back into worldspawn, just right-click in the 2D view and choose *Revert to worldspawn*. *Merge selected entities*:: Convert two more more selected entities into a single entity which contains all of the contained brushes and patches. Only works for entities which can contain primitives (e.g. func_static). *Copy shader*:: Copy the shader from the selected face to the <>. *Paste shader*:: Paste the shader currently on the <> to all selected faces. *Clear selection*:: De-select all selected objects. *Invert selection*:: De-select all selected objects, and select all unselected objects. *Select complete tall*:: Convert the currently-selected brush into a selection volume, selecting all objects which are completely contained within its outline in the current 2D view (ignoring the third dimension). See <>. *Select inside*:: Convert the currently-selected brush into a selection volume, selecting all objects which are completely contained within it in all three dimensions. See <>. *Select fully inside*:: Like *Select inside*, except that contained brushes which touch the boundary of the selection brush will not be selected. *Select children*:: Select primitives which are children of the currently-selected entity. See <>. *Select parent entities*:: Select the parent entity of the currently-selected primitive. See <>. === View menu *New XY view*:: Create a new dockable orthographic (2D) view. *New Camera view*:: Create a new dockable 3D camera view. *Colours...*:: Show a dialog for choosing and editing <>. === Entity menu *Connect selected entities*:: Set a `target` spawnarg on the first selected entity pointing to the second selected entity. *Bind selected entities*:: Set a `bind` spawnarg on the first selected entity pointing to the second selected entity. *Entity class tree...*:: Show a tree of all available entity types in the current game, along with all of their properties. Unlike the tree shown in the *Create Entity* dialog, this entity class tree shows an inheritance-based hierarchy and does not include a 3D preview. === Brush menu *Prism...*:: Create an angular prism (extruded polygon) from the selected brush. See <>. *Cone...*:: Create a cone or pyramid from the selected brush. See <>. *Sphere...*:: Create an approximation of a sphere from the selected brush. See <>. *CSG -> Make Hollow*:: Create a hollow room from the selected brush. See <>. *CSG -> Make Room*:: Create a hollow room from the selected brush, without any overlapping walls. See <>. *Clipper -> Clip Selection*:: Split the selected brush along the defined clip plane, keeping one half. See <>. *Clipper -> Split Selection*:: Split the selected brush along the defined clip plane, keeping both halves. See <>. *Clipper -> Flip Clip Orientation*:: Change which half of the brush is retained after using the *Clip Selection* command. Difficult to use in practice; instead just *Split Selection* and delete the unwanted half manually. See <>. *Make Detail / Make Structural*:: These options only exist to support legacy games, and are not used in the Dark Mod. == Configuring DarkRadiant DarkRadiant offers a large number of configurable options which can be used to tailor its behaviour to your desired workflow. Most of these options can be found either in the Preferences dialog or exposed directly as menu items. === The Preferences dialog The Preferences dialog can be shown by choosing `Preferences...` from the `Edit` menu. The dialog contains a number of pages containing groups of logically related options. ==== Camera settings The *Camera* page contains options relating to the movement and behaviour of the 3D camera. *Movement Speed*:: Use this slider to control how many game units the camera moves forwards or backwards when you use the scroll wheel in the 3D view. It does not affect the speed of rotation or lateral dragging (e.g. with *Ctrl*) in free look mode, nor does it affect motion with the arrow keys. *Rotation Speed*:: This controls the speed of angular rotation when dragging the mouse after entering free look mode with right-click. If you have a high DPI mouse and want to be able to direct the camera more precisely, reducing this setting may help. *Freelook mode can be toggled*:: Disabling this checkbox makes the free look functionality behave more like typical MMO games, where you hold down the right mouse button and drag to move the camera around. Uncheck this option if you hate modal interfaces or find the default toggle behaviour confusing. *Discrete movement (non-freelook mode)*:: If this is checked, moving the camera with the arrow keys in non-freelook mode will cause discrete jumps in position, rather than smooth motion. *Enable far clip plane*:: You can completely disable the <> by unchecking this option. This will avoid the need to manage the position of the far clip plane, but may negatively impact rendering performance in large or complex maps. + NOTE: Technically it is not actually possible to _disable_ the far clip plane, since having a far clip plane is a requirement for 3D rendering to work correctly. This command in fact sets the far clip plane to a very high value, e.g. 32768. If your map is very large, it is conceivable that you will still see some far clipping behaviour. *Invert mouse vertical axis*:: Enable this option to flip the sense of the vertical camera motion when freelook mode is enabled, so that moving the mouse upwards tilts the camera downwards, and vice versa. *Solid selection boxes*:: This option controls whether selected brushes are drawn with a dashed outline (option disabled) or a solid line (option enabled). It affects both the 2D and the 3D views. *Show camera toolbar*:: Uncheck this to completely hide the toolbar at the top of the 3D camera window (which includes the render mode buttons and the far clip plane controls). ==== Orthoview settings The *Orthoview* page contains options controlling the display and behaviour of the 2D views. *View chases mouse cursor during drags*:: If this is enabled, dragging an object off the edge of a 2D view will cause the 2D view to automatically scroll to keep the dragged object in view. If disabled, the dragged object will reach the edge and stop. You can control the speed of the scrolling with the *Maximum Chase Mouse Speed* slider. *Update views on camera movement*:: This option controls whether the camera position indicator in the 2D views is automatically kept in sync with camera movements in the 3D window. If this option is disabled, the 2D view camera indicator may not move until you explicitly click on or interact with a 2D view. *Show crosshairs*:: Enable this option to display full-window-sized crosshairs tracking the mouse cursor whenever it moves over a 2D window. This may assist with precise selection or object alignment. *Show grid*:: Control the visibility of grid lines in the 2D views. This does not affect the snapping behaviour, just the visual rendering of the grid. *Show blocks*:: If enabled, the world space is divided into a horizontal grid of 1024x1024 unit blocks (of infinite height) which are outlined in blue in the 2D views. Each block is assigned a pair of numbers representing its position from the centermost block, which is assigned `(0, 0)`. This might help with "blocking out" a map at the beginning of the design phase. This option is also available in the `View -> Show` menu. *Translate manipulator always constrained to axis*:: This option affects the behaviour of the <>. When the option is disabled, dragging a selected object in translation mode will behave as if the manipulator's *central square* is being dragged, and allow motion in two dimensions. If the option is enabled, dragging the selected object will behave as if the closest manipulator *arrow* is being dragged, and allow motion along only a single axis. Translation in two dimensions will always be possible by clicking on the manipulator's central square directly, regardless of the state of this option. *Higher selection priority for entities*:: When using the mouse to click on and select an entity which is in front of, behind or inside a brush, this option controls whether DarkRadiant will prefer to select the entity (enabled) or the brush (disabled). ==== User Interface settings *Start on Monitor*:: If you have more than one monitor, you can choose which monitor DarkRadiant will start on using this combo box. *Source view font size*:: This controls the point size of the monospace font used in source code view widgets, such as those which show material or skin source declarations. *Language*:: This combo box lists all of the installed language packs, allowing you to choose which language is used for the DarkRadiant interface. ==== Autosave settings *Enable Autosave*:: Controls whether the autosave feature is active or disabled. *Autosave Interval*:: Use this slider to choose how often DarkRadiant will make an autosave. By default, autosaves are made every 5 minutes. *Save Snapshots*:: If this option is enabled, DarkRadiant will make each autosave into a separate copy of the map file, allowing you to potentially revert changes which were made several autosaves ago. If this option is disabled, there will only ever be a single autosave file, which will protect against DarkRadiant or system crashes but not against long-term erroneous changes. *Snapshot folder*:: This specifies the name of the folder used to store snapshot autosaves, if the *Save Snapshots* option is enabled. *Max Snapshot size per map*:: This allows you to control the amount of disk space used for storing snapshots, by specifying a maximum number of megabytes that will be used for storing the snapshots for a single map. If the disk usage grows above this limit, DarkRadiant will start to delete old snapshots. ==== Clipper settings *Clipper tool uses caulk texture*:: If this option is enabled, the <> will texture the newly-created clip face with the texture specified in the *Caulk shader name* text field. If the option is disabled, the new face will be given the same texture as the rest of the brush. ==== Grid settings This page contains a couple of options relating to the appearance and default behaviour of the grid. *Default grid size*:: Use this combo box to choose the default grid size used in new projects (to change the grid size in the _current_ project, use the options in the *Grid* main menu). *Major grid style*:: Choose the rendering style for the major grid lines. Available options are *Lines*, *Dotted Lines*, *More Dotted Lines*, *Crosses*, *Dots*, *Big Dots*, and *Squares*. *Minor grid style*:: Choose the rendering style for the minor grid lines. Available options are the same as the *Major grid style* combo box. ==== Selection settings *Ignore light volume bounds when calculating default rotation pivot location*:: This option affects the behaviour of the <> when multiple objects are selected. DarkRadiant will place the rotation widget at the approximate "center of gravity" of the set of selected objects. If this option is enabled, any selected lights will be treated as point entities, with no volume in 3D space regardless of their actual light volumes. If this option is disabled, the entire light volume will be taken into account as if the light were a rectangular brush. ==== Undo settings *Undo Queue Size*:: Use this spinbox to control the number of operations which are saved onto DarkRadiant's internal undo stack. Larger values provide a longer history of undoable operations, at the expense of requiring more memory. ==== Primitives settings This page contains two options controlling the default behaviour of applied textures. These values can be set on a per-object basis using the <>. *Default texture scale*:: Set a default scale factor for newly applied textures. *Enable texture lock*:: Set the default value of the Texture Lock button. See the <> section for more details on this feature. ==== Texture Browser settings These options control the behaviour of the <>. *Uniform texture thumbnail size*:: Choose the size in pixels that will be used for texture thumbnails. *Texture scrollbar*:: Hide or show the scrollbar in the textures tab. If the scrollbar is hidden, scrolling is only possible with the mouse wheel. *Mousewheel increment*:: This option determines how much the window is scrolled when the mouse wheel is rotated. *Max shadername length*:: Choose the maximum number of characters that may appear in each texture name. If a texture contains more characters than this, the texture name will be abbreviated with "..." in the middle. ==== Map files settings *Number of most recently used files*:: Choose the number of map files to list in the recent map section at the bottom of the *File* menu. *Open last map on startup*:: Enable this option to make DarkRadiant automatically load the most recently-used map every time it starts, rather than starting with an empty map. == Features for game distributors DarkRadiant is designed to work out of the box with a standard Doom 3 or Dark Mod game installation, however it also offers a few features aimed at developers of the game itself. === Controlling asset visibility As the development of a game progresses, certain assets may become obsolete or deprecated, either because they are no longer needed or because they fall short of the quality standard that is expected of new assets. If these assets have already been distributed, removing them from the game installation may be problematic, as maps which depend on them will fail to load correctly. DarkRadiant offers a mechanism to deal with this by allowing certain assets to be marked as "hidden". A hidden asset will no longer be presented for selection by the user (e.g. on the Media tab or in the Model selector), but will continue to function as normal when it appears in a loaded map. The mechanism for hiding assets depends on the asset type: models, materials, particles and sound shaders use a file-based `assets.lst` approach, whereas entity classes use a dedicated spawnarg. ==== Hiding models, materials, particles or sound shaders To change the visibility of these types of asset, you need to create a file called `assets.lst` which resides in the top-level `models`, `materials`, `particles` or `sound` directory in the mod installation. This file may be inside a PK4 or in an extracted directory tree. The contents of `assets.lst` are a simple list of key/value pairs, assigning a visibility value to each named asset. For example: .assets.lst ---- darkmod/chairs/some_broken_chair.lwo=hidden darkmod/tables/another_table.ase=hidden ---- Asset paths listed on the left-hand side are interpreted relative to the directory containing `assets.lst`. The visibility value on the right-hand side must be either `hidden` or `normal`; a value of `normal` is equivalent to not listing the file at all, and results in no change to its visibility. NOTE: Only *files* may be listed in an `assets.lst`, not items in a virtual hierarchy such as the material shader tree. When a `.mtr` or `.sndshd` file is listed as hidden, all shaders contained within it will be hidden in DarkRadiant. This means that in order to hide specific shaders, you must move these into one or more source files which are listed as hidden. ==== Hiding entities To hide an entity class, edit the `.def` file and set a "editor_visibility" spawnarg on the entity class, giving it the value "hidden". This will cause the entity class to be hidden from the Create Entity dialog and any other entity class chooser. The visibility spawnarg is not inherited, which makes it possible to hide a base class (perhaps because it should not be created directly), without affecting the visibility of entity classes which inherit from it. ================================================ FILE: doc/manual.css ================================================ /* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */ @import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700"; article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block} audio,canvas,video{display:inline-block} audio:not([controls]){display:none;height:0} [hidden],template{display:none} script{display:none!important} html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%} body{margin:0} a{background:transparent} a:focus{outline:thin dotted} a:active,a:hover{outline:0} h1{font-size:2em;margin:.67em 0} abbr[title]{border-bottom:1px dotted} b,strong{font-weight:bold} dfn{font-style:italic} hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0} mark{background:#ff0;color:#000} code,kbd,pre,samp{font-family:monospace;font-size:1em} pre{white-space:pre-wrap} q{quotes:"\201C" "\201D" "\2018" "\2019"} small{font-size:80%} sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} sup{top:-.5em} sub{bottom:-.25em} img{border:0} svg:not(:root){overflow:hidden} figure{margin:0} fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em} legend{border:0;padding:0} button,input,select,textarea{font-family:inherit;font-size:100%;margin:0} button,input{line-height:normal} button,select{text-transform:none} button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer} button[disabled],html input[disabled]{cursor:default} input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0} input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none} button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0} textarea{overflow:auto;vertical-align:top} table{border-collapse:collapse;border-spacing:0} *,*:before,*:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box} html,body{font-size:110%} body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Open Sans",sans-serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto} a:hover{cursor:pointer} img,object,embed{max-width:100%;height:auto} object,embed{height:100%} img{-ms-interpolation-mode:bicubic} .left{float:left!important} .right{float:right!important} .text-left{text-align:left!important} .text-right{text-align:right!important} .text-center{text-align:center!important} .text-justify{text-align:justify!important} .hide{display:none} body{-webkit-font-smoothing:antialiased} img,object,svg{display:inline-block;vertical-align:middle} textarea{height:auto;min-height:50px} select{width:100%} .center{margin-left:auto;margin-right:auto} .spread{width:100%} p.lead,.paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{font-size:1.21875em;line-height:1.6} .subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em} div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr} a{color:#2156a5;text-decoration:underline;line-height:inherit} a:hover,a:focus{color:#1d4b8f} a img{border:none} p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility} p aside{font-size:.875em;line-height:1.35;font-style:italic} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:bold;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em} h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0} h1{font-size:2.125em} h2{font-size:1.6875em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em} h4,h5{font-size:1.125em} h6{font-size:1em} hr{border:solid #ddddd8;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0} em,i{font-style:italic;line-height:inherit} strong,b{color:#7a2518;font-weight:bold;line-height:inherit} small{font-size:60%;line-height:inherit} code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)} ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit} ul,ol,ul.no-bullet,ol.no-bullet{margin-left:1.5em} ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em} ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit} ul.square{list-style-type:square} ul.circle{list-style-type:circle} ul.disc{list-style-type:disc} ul.no-bullet{list-style:none} ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0} dl dt{margin-bottom:.3125em;font-weight:bold} dl dd{margin-bottom:1.25em} abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help} abbr{text-transform:none} blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd} blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)} blockquote cite:before{content:"\2014 \0020"} blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)} blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)} @media only screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2} h1{font-size:2.75em} h2{font-size:2.3125em} h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em} h4{font-size:1.4375em}} table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede} table thead,table tfoot{background:#f7f8f7;font-weight:bold} table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left} table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)} table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6} body{tab-size:4} h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em} h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400} .clearfix:before,.clearfix:after,.float-group:before,.float-group:after{content:" ";display:table} .clearfix:after,.float-group:after{clear:both} *:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed} pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed} .keyseq{color:rgba(51,51,51,.8)} kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap} .keyseq kbd:first-child{margin-left:0} .keyseq kbd:last-child{margin-right:0} .menuseq,.menu{color:rgba(0,0,0,.8)} b.button:before,b.button:after{position:relative;top:-1px;font-weight:400} b.button:before{content:"[";padding:0 3px 0 2px} b.button:after{content:"]";padding:0 2px 0 3px} p a>code:hover{color:rgba(0,0,0,.9)} #header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em} #header:before,#header:after,#content:before,#content:after,#footnotes:before,#footnotes:after,#footer:before,#footer:after{content:" ";display:table} #header:after,#content:after,#footnotes:after,#footer:after{clear:both} #content{margin-top:1.25em} #content:before{content:none} #header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0} #header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #ddddd8} #header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #ddddd8;padding-bottom:8px} #header .details{border-bottom:1px solid #ddddd8;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap} #header .details span:first-child{margin-left:-.125em} #header .details span.email a{color:rgba(0,0,0,.85)} #header .details br{display:none} #header .details br+span:before{content:"\00a0\2013\00a0"} #header .details br+span.author:before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)} #header .details br+span#revremark:before{content:"\00a0|\00a0"} #header #revnumber{text-transform:capitalize} #header #revnumber:after{content:"\00a0"} #content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #ddddd8;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem} #toc{border-bottom:1px solid #efefed;padding-bottom:.5em} #toc>ul{margin-left:.125em} #toc ul.sectlevel0>li>a{font-style:italic} #toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0} #toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none} #toc li{line-height:1.3334;margin-top:.3334em} #toc a{text-decoration:none} #toc a:active{text-decoration:underline} #toctitle{color:#7a2518;font-size:1.2em} @media only screen and (min-width:768px){#toctitle{font-size:1.375em} body.toc2{padding-left:15em;padding-right:0} #toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #efefed;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto} #toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em} #toc.toc2>ul{font-size:.9em;margin-bottom:0} #toc.toc2 ul ul{margin-left:0;padding-left:1em} #toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em} body.toc2.toc-right{padding-left:0;padding-right:15em} body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #efefed;left:auto;right:0}} @media only screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0} #toc.toc2{width:20em} #toc.toc2 #toctitle{font-size:1.375em} #toc.toc2>ul{font-size:.95em} #toc.toc2 ul ul{padding-left:1.25em} body.toc2.toc-right{padding-left:0;padding-right:20em}} #content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} #content #toc>:first-child{margin-top:0} #content #toc>:last-child{margin-bottom:0} #footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em} #footer-text{color:rgba(255,255,255,.8);line-height:1.44} .sect1{padding-bottom:.625em} @media only screen and (min-width:768px){.sect1{padding-bottom:1.25em}} .sect1+.sect1{border-top:1px solid #efefed} #content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:left;font-weight:400} #content h1>a.anchor:before,h2>a.anchor:before,h3>a.anchor:before,#toctitle>a.anchor:before,.sidebarblock>.content>.title>a.anchor:before,h4>a.anchor:before,h5>a.anchor:before,h6>a.anchor:before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em} #content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible} #content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none} #content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221} .audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em} .admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic} table.tableblock>caption.title{white-space:nowrap;overflow:visible;max-width:0} .paragraph.lead>p,#preamble>.sectionbody>.paragraph:first-of-type p{color:rgba(0,0,0,.85)} table.tableblock #preamble>.sectionbody>.paragraph:first-of-type p{font-size:inherit} .admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%} .admonitionblock>table td.icon{text-align:center;width:80px} .admonitionblock>table td.icon img{max-width:none} .admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase} .admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #ddddd8;color:rgba(0,0,0,.6)} .admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0} .exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px} .exampleblock>.content>:first-child{margin-top:0} .exampleblock>.content>:last-child{margin-bottom:0} .sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px} .sidebarblock>:first-child{margin-top:0} .sidebarblock>:last-child{margin-bottom:0} .sidebarblock>.content>.title{color:#7a2518;margin-top:0;margin-bottom:1em;text-align:left;font-size:1.1em;font-weight:bold;} .exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0} .literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8} .sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1} .literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;padding:1em;font-size:.8125em} .literalblock pre.nowrap,.literalblock pre[class].nowrap,.listingblock pre.nowrap,.listingblock pre[class].nowrap{overflow-x:auto;white-space:pre;word-wrap:normal} @media only screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}} @media only screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}} .literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)} .listingblock pre.highlightjs{padding:0} .listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px} .listingblock pre.prettyprint{border-width:0} .listingblock>.content{position:relative} .listingblock code[data-lang]:before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999} .listingblock:hover code[data-lang]:before{display:block} .listingblock.terminal pre .command:before{content:attr(data-prompt);padding-right:.5em;color:#999} .listingblock.terminal pre .command:not([data-prompt]):before{content:"$"} table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none} table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45} table.pyhltable td.code{padding-left:.75em;padding-right:0} pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #ddddd8} pre.pygments .lineno{display:inline-block;margin-right:.25em} table.pyhltable .linenodiv{background:none!important;padding-right:0!important} .quoteblock{margin:0 1em 1.25em 1.5em;display:table} .quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em} .quoteblock blockquote,.quoteblock blockquote p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify} .quoteblock blockquote{margin:0;padding:0;border:0} .quoteblock blockquote:before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)} .quoteblock blockquote>.paragraph:last-child p{margin-bottom:0} .quoteblock .attribution{margin-top:.5em;margin-right:.5ex;text-align:right} .quoteblock .quoteblock{margin-left:0;margin-right:0;padding:.5em 0;border-left:3px solid rgba(0,0,0,.6)} .quoteblock .quoteblock blockquote{padding:0 0 0 .75em} .quoteblock .quoteblock blockquote:before{display:none} .verseblock{margin:0 1em 1.25em 1em} .verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility} .verseblock pre strong{font-weight:400} .verseblock .attribution{margin-top:1.25rem;margin-left:.5ex} .quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic} .quoteblock .attribution br,.verseblock .attribution br{display:none} .quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)} .quoteblock.abstract{margin:0 0 1.25em 0;display:block} .quoteblock.abstract blockquote,.quoteblock.abstract blockquote p{text-align:left;word-spacing:0} .quoteblock.abstract blockquote:before,.quoteblock.abstract blockquote p:first-of-type:before{display:none} table.tableblock{max-width:100%;border-collapse:separate} table.tableblock td>.paragraph:last-child p>p:last-child,table.tableblock th>p:last-child,table.tableblock td>p:last-child{margin-bottom:0} table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede} table.grid-all th.tableblock,table.grid-all td.tableblock{border-width:0 1px 1px 0} table.grid-all tfoot>tr>th.tableblock,table.grid-all tfoot>tr>td.tableblock{border-width:1px 1px 0 0} table.grid-cols th.tableblock,table.grid-cols td.tableblock{border-width:0 1px 0 0} table.grid-all *>tr>.tableblock:last-child,table.grid-cols *>tr>.tableblock:last-child{border-right-width:0} table.grid-rows th.tableblock,table.grid-rows td.tableblock{border-width:0 0 1px 0} table.grid-all tbody>tr:last-child>th.tableblock,table.grid-all tbody>tr:last-child>td.tableblock,table.grid-all thead:last-child>tr>th.tableblock,table.grid-rows tbody>tr:last-child>th.tableblock,table.grid-rows tbody>tr:last-child>td.tableblock,table.grid-rows thead:last-child>tr>th.tableblock{border-bottom-width:0} table.grid-rows tfoot>tr>th.tableblock,table.grid-rows tfoot>tr>td.tableblock{border-width:1px 0 0 0} table.frame-all{border-width:1px} table.frame-sides{border-width:0 1px} table.frame-topbot{border-width:1px 0} th.halign-left,td.halign-left{text-align:left} th.halign-right,td.halign-right{text-align:right} th.halign-center,td.halign-center{text-align:center} th.valign-top,td.valign-top{vertical-align:top} th.valign-bottom,td.valign-bottom{vertical-align:bottom} th.valign-middle,td.valign-middle{vertical-align:middle} table thead th,table tfoot th{font-weight:bold} tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7} tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:#7a2518;font-weight:bold} p.tableblock>code:only-child{background:none;padding:0} p.tableblock{font-size:1em} td>div.verse{white-space:pre} ol{margin-left:1.75em} ul li ol{margin-left:1.5em} dl dd{margin-left:1.125em} dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0} ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em} ul.unstyled,ol.unnumbered,ul.checklist,ul.none{list-style-type:none} ul.unstyled,ol.unnumbered,ul.checklist{margin-left:.625em} ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1em;font-size:.85em} ul.checklist li>p:first-child>input[type="checkbox"]:first-child{width:1em;position:relative;top:1px} ul.inline{margin:0 auto .625em auto;margin-left:-1.375em;margin-right:0;padding:0;list-style:none;overflow:hidden} ul.inline>li{list-style:none;float:left;margin-left:1.375em;display:block} ul.inline>li>*{display:block} .unstyled dl dt{font-weight:400;font-style:normal} ol.arabic{list-style-type:decimal} ol.decimal{list-style-type:decimal-leading-zero} ol.loweralpha{list-style-type:lower-alpha} ol.upperalpha{list-style-type:upper-alpha} ol.lowerroman{list-style-type:lower-roman} ol.upperroman{list-style-type:upper-roman} ol.lowergreek{list-style-type:lower-greek} .hdlist>table,.colist>table{border:0;background:none} .hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none} td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em} td.hdlist1{font-weight:bold;padding-bottom:1.25em} .literalblock+.colist,.listingblock+.colist{margin-top:-.5em} .colist>table tr>td:first-of-type{padding:0 .75em;line-height:1} .colist>table tr>td:last-of-type{padding:.25em 0} .thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd} .imageblock.left,.imageblock[style*="float: left"]{margin:.25em .625em 1.25em 0} .imageblock.right,.imageblock[style*="float: right"]{margin:.25em 0 1.25em .625em} .imageblock>.title { font-family:"Open Sans",sans-serif; margin-bottom:0; text-align:center; } .imageblock.thumb,.imageblock.th{border-width:6px} .imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em} .image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0} .image.left{margin-right:.625em} .image.right{margin-left:.625em} a.image{text-decoration:none;display:inline-block} a.image object{pointer-events:none} sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super} sup.footnote a,sup.footnoteref a{text-decoration:none} sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline} #footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em} #footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em 0;border-width:1px 0 0 0} #footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;text-indent:-1.05em;margin-bottom:.2em} #footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none} #footnotes .footnote:last-of-type{margin-bottom:0} #content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0} .gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0} .gist .file-data>table td.line-data{width:99%} div.unbreakable{page-break-inside:avoid} .big{font-size:larger} .small{font-size:smaller} .underline{text-decoration:underline} .overline{text-decoration:overline} .line-through{text-decoration:line-through} .aqua{color:#00bfbf} .aqua-background{background-color:#00fafa} .black{color:#000} .black-background{background-color:#000} .blue{color:#0000bf} .blue-background{background-color:#0000fa} .fuchsia{color:#bf00bf} .fuchsia-background{background-color:#fa00fa} .gray{color:#606060} .gray-background{background-color:#7d7d7d} .green{color:#006000} .green-background{background-color:#007d00} .lime{color:#00bf00} .lime-background{background-color:#00fa00} .maroon{color:#600000} .maroon-background{background-color:#7d0000} .navy{color:#000060} .navy-background{background-color:#00007d} .olive{color:#606000} .olive-background{background-color:#7d7d00} .purple{color:#600060} .purple-background{background-color:#7d007d} .red{color:#bf0000} .red-background{background-color:#fa0000} .silver{color:#909090} .silver-background{background-color:#bcbcbc} .teal{color:#006060} .teal-background{background-color:#007d7d} .white{color:#bfbfbf} .white-background{background-color:#fafafa} .yellow{color:#bfbf00} .yellow-background{background-color:#fafa00} span.icon>.fa{cursor:default} .admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default} .admonitionblock td.icon .icon-note:before{content:"\f05a";color:#19407c} .admonitionblock td.icon .icon-tip:before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111} .admonitionblock td.icon .icon-warning:before{content:"\f071";color:#bf6900} .admonitionblock td.icon .icon-caution:before{content:"\f06d";color:#bf3400} .admonitionblock td.icon .icon-important:before{content:"\f06a";color:#bf0000} .conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold} .conum[data-value] *{color:#fff!important} .conum[data-value]+b{display:none} .conum[data-value]:after{content:attr(data-value)} pre .conum[data-value]{position:relative;top:-.125em} b.conum *{color:inherit!important} .conum:not([data-value]):empty{display:none} dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility} h1,h2,p,td.content,span.alt{letter-spacing:-.01em} p strong,td.content strong,div.footnote strong{letter-spacing:-.005em} p{margin-bottom:1.25rem} .sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em} .exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc} .print-only{display:none!important} @media print{@page{margin:1.25cm .75cm} *{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important} a{color:inherit!important;text-decoration:underline!important} a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important} a[href^="http:"]:not(.bare):after,a[href^="https:"]:not(.bare):after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em} abbr[title]:after{content:" (" attr(title) ")"} pre,blockquote,tr,img,object,svg{page-break-inside:avoid} thead{display:table-header-group} svg{max-width:100%} p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3} h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid} #toc,.sidebarblock,.exampleblock>.content{background:none!important} #toc{border-bottom:1px solid #ddddd8!important;padding-bottom:0!important} .sect1{padding-bottom:0!important} .sect1+.sect1{border:0!important} #header>h1:first-child{margin-top:1.25rem} body.book #header{text-align:center} body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em 0} body.book #header .details{border:0!important;display:block;padding:0!important} body.book #header .details span:first-child{margin-left:0!important} body.book #header .details br{display:block} body.book #header .details br+span:before{content:none!important} body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important} body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always} .listingblock code[data-lang]:before{display:block} #footer{background:none!important;padding:0 .9375em} #footer-text{color:rgba(0,0,0,.6)!important;font-size:.9em} .hide-on-print{display:none!important} .print-only{display:block!important} .hide-for-print{display:none!important} .show-for-print{display:inherit!important}} ================================================ FILE: doc/manual.html ================================================ DarkRadiant User Guide

Introduction

DarkRadiant is a level editor for Doom 3 and The Dark Mod, developed by The Dark Mod team. It may also be used for editing levels for similar id Software games such as Quake 4.

This User Guide describes the features and functionality of DarkRadiant, however it is not intended as a guide to mapping techniques. Level design is a complex topic, and is covered by various other learning resources, some of which are listed below.

The Dark Mod Wiki

The starting point for most Dark Mod documentation and tutorials, including gameplay, configuration and editing.

ModWiki

Online wiki covering editing topics for vanilla Doom 3 and similar engines.

The Dark Mod forums

Online community for discussion of the Dark Mod, including various ad-hoc mapping tutorial threads posted by individual users.

Editing workflow

DarkRadiantWorkflow

The level editing process starts off with basic assets: models, textures, sounds, entity definitions, skins, animations and so on. Many of these assets will be packaged with a particular game installation, but a level designer may also choose to create custom assets for a specific mission. These assets are installed into a directory tree which is accessible both by DarkRadiant (for editing) and the game engine itself (for playing the mission).

Once assets have been arranged in DarkRadiant according to the wishes of the level designer, a .map file is saved to disk. This is a text file in a format understood by the game engine, and includes both level geometry and references to the assets used in the map. Since the .map file is simply text, and does not actually embed the binary asset data, it tends to be fairly small.

The game engine includes functionality to compile the .map file into a .proc file containing low-level vertex geometry derived from the brushes and patches within the .map file. The game engine can then render the mission in realtime, making use of the same assets that were accessed by DarkRadiant during editing.

DarkRadiant also maintains its own separate file containing various editing information, such as object layers used within a map. This .darkradiant file is never used by the game engine, and is non-critical — a .map file with no accompanying .darkradiant file can still be edited with DarkRadiant, although certain DarkRadiant-specific state may be lost.

What’s in a MAP?

There are three main types of object contained within a .map file: entities, brushes and patches.

Entities are the top-level objects in a map — essentially, a map file is just a list of entities. Every entity has an entity class which determines the type of entity it is: static mesh, AI, sound emitter, particle emitter, light etc. Entities also store a list of string key/value pairs, known as spawnargs or properties. Some entities also contain brushes and patches as children.

Brushes are convex solids used to define basic map geometry: walls, floors, ceilings, steps and other medium to large items. Brushes are often rectangular in shape, although a brush can actually have any number of faces provided that it is convex (it is impossible to have a brush in an L or a U shape, for example). Brushes are not smooth-shaded by the game engine, which generally makes them unsuitable for representing curved surfaces.

Patches are smooth one-sided surfaces used to represent curved objects such as vaulted ceilings, pillars or cave interiors. A patch is defined by a number of Bezier control points, and offers control over the level of detail used when subdividing the patch into triangles for rendering: more triangles will produce a smoother surface but may lower rendering performance.

Brushes and patches together are also referred to as primitives (since they define the basic geometry of the map), and are typically described as such in situations where the distinction between brush and patch is not important.

The entities, brushes and patches in a map are arranged in a hierarchy: not every entity has children, but every primitive must have an entity as a parent. Each map therefore starts with a single default entity called the worldspawn, which acts as the parent for new brushes and patches created in DarkRadiant.

Initial configuration

Choosing a game type

When running DarkRadiant for the first time, the Game Setup dialog will be shown. This is where you configure the path to the game installation from which DarkRadiant will load assets, such as textures, models and entity definitions.

GameSetupDialog

The Game Setup dialog contains the following options:

Game Type

DarkRadiant ships with support for several different game engines, each of which is contained within a .game file. For editing Dark Mod missions, the default choice of The Dark Mod 2.0 (Standalone) is the one to use, but it is also possible to edit stock Doom 3 or Quake 4 missions.

DarkMod Path / Engine Path

This is the path to the game installation on the system. The label text will change depending on whether the selected game is The Dark Mod or another engine.

Mission

Optional path to a subdirectory containing assets specific to a particular mission which is being worked on. For game types other than The Dark Mod, this will be displayed as Mod (fs_game), and should be set to the path of a subdirectory containing a particular game mod, if one is being used.

Mod Base (fs_game_base)

This field only appears for non-DarkMod game types. It allows a two-level mod structure, where the Mod Base can point to a major game mod, possibly downloaded from elsewhere, while Mod can be set to point to an entirely local "sub-mod" which contains local changes and overrides. Before the release of Dark Mod standalone, this field would have been set to darkmod while the Mod field would have been set to the local mission, however this is no longer necessary when The Dark Mod 2.0 (Standalone) is being used.

Once the game paths are set up, click the Save button to proceed to the main DarkRadiant interface.

Note It is possible to Cancel the Game Setup dialog and proceed to the main window without configuring a game installation, in which case DarkRadiant will show a warning and ask if you wish to proceed. If you do, DarkRadiant will run but there will be no available textures, models, entities or other game assets.

Interface layout

DarkRadiant uses a flexible layout system based on dockable windows which can be moved into various positions around the edges of the main window, or floated as separate top-level windows. The arrangement and sizes of these windows are saved into settings and persisted between sessions.

Each window has a small title bar at the top showing the window’s name. Dragging this title bar will allow the docked window to be floated or docked into a different position depending on the drag destination. When the window is dragged near a possible dock position, a shaded rectangle will appear indicating where the window will be docked.

There is a central 2D view which cannot be undocked or replaced, although it can be made arbitrarily small by expanding docked widgets towards the center. Likewise, the camera view and properties panels cannot be removed, although they can be resized and moved into different dock positions.

You can create additional 2D and camera views using the View → New XY view and View → New Camera view menu items. These additional views can be floated or docked like the main windows, and can also be removed by clicking the X button at the top right of the title bar. All 2D views store their orientation (XY/YZ/XZ) into settings, which makes it possible to set up a traditional 3D modelling interface with three orthographic views and a camera view, if desired.

Colour schemes

DarkRadiant defaults to a black-on-white colour scheme in the 2D windows, but ships with four other colour schemes, which can be chosen with the View → Colours…​ dialog. If you prefer a dark theme, the Black & Green scheme might be suitable, whereas the Maya/Max/Lightwave Emulation and Super Mal themes provide a more neutral, low-contrast look.

Colour schemes only affect what is rendered in the 2D and 3D views by DarkRadiant itself. The appearance of the user interface is determined by the wxWidgets toolkit based on the system-wide widget theme, and can only be changed via system settings or other applications (such as gnome-tweaks on Linux).

DarkRadiantDefaultTheme
DarkRadiant Default

BlackGreenTheme
Black and Green

Q3RadiantTheme
QE3Radiant Original

SuperMalTheme
Super Mal

MayaEmulationTheme
Maya/Max/Lightwave Emulation

Each of the colour schemes can be edited using the colour selector buttons in the Colours dialog, and it is also possible to copy one of the default schemes into a custom scheme with a new name.

Note The game installation may specify the colour of certain entity types, in which case it will not be possible to change the colour of these entities via the Colours dialog.

Basic editing

Navigating the 2D view

The game world is a three-dimensional vector space with a central origin, rendered in the 2D editing window as a grid. The unit of measurement is an arbitrary game unit which does not directly correspond to any real-world measurement system — in The Dark Mod, a typical human stands around 80 - 90 game units high, making a game unit about 2 cm.

Each 2D window shows which axes it is representing with an icon in the top-left corner, as well as an identical icon at the <0,0,0> origin position, if visible within the view.

2DViewMarkedUp
Figure 1. Components of the 2D view

The 2D view also shows the current position of the camera (used for rendering the separate 3D camera view window), and its view direction.

The following commands are available within the 2D view:

Right drag

Scroll the view horizontally or vertically

Mouse wheel

Zoom the view

Shift + Right drag

Zoom the view (alternative binding)

Ctrl + Middle click

Move the camera directly to the clicked position

Middle click

Rotate the camera to look directly at the clicked point

Ctrl + TAB

Change view axis (XY, XZ, YZ)

Ctrl + Shift + TAB

Center 2D view on current camera position

Adjusting the grid

The grid shown in the 2D view is used to snap the position and size of brushes and patches, as well as the centerpoints of entities. The size of the grid can be configured, in powers of 2, from 0.125 up to 256, using the 1-9 keys on the main keyboard (not the numeric keypad), or the equivalent options in the Grid menu.

The 0 key on the main keyboard can be used to toggle the display of the grid. Note that objects will still be snapped to the grid even if the grid is not visible; this is purely a visual toggle.

Important Level geometry built from brushes and patches should always be snapped to the grid to avoid problems such as rendering glitches and map leaks. Static meshes and animated AI can be positioned more freely, however grid snapping is a useful tool for ensuring that models are appropriately aligned with the level geometry.

Customising the grid appearance

The appearance of the grid can be customised using the options in the Grid tab of the Edit → Preferences dialog. Separate styles can be chosen for major and minor grid lines.

GridStyleLines
Lines

GridStyleDottedLines
Dotted Lines

GridStyleMoreDottedLines
More Dotted Lines

GridStyleSquares
Squares

GridStyleDots
Dots

GridStyleBigDots
Big Dots

Adding a background image

The 2D view is capable of showing a background image, which may be useful to show image references, or sketched 2D maps to guide the placement of level geometry.

To show a background image, choose View → Background image…​ which will show the background image configuration dialog.

Use background image

Master toggle to show or hide the background image.

Image file

Click on the widget to show a file chooser which allows you to find and *select the background image to show.

Opacity

Drag the slider to control the opacity of the image, from fully transparent *(invisible) to fully opaque.

Scale

Adjusts the size of the image.

Horiz. offset

Adjusts the position of the image from left to right.

Vert. offset

Adjusts the position of the image from top to bottom.

Keep aspect

If checked, the image will always be displayed at its native aspect ratio. If unchecked, the image will have the same aspect ratio as the containing 2D view.

Zoom with viewport

If checked, the image will change size as the 2D view is zoomed in or out. If unchecked, the image will always have the same size regardless of the 2D window zoom.

Pan with viewport

If checked, the image will be anchored in 2D space, and will stay in the same position relative to the world as the 2D view is panned. If unchecked, the image will always have the same position relative to the window, and the world geometry will pan around it.

Using the 3D camera view

The 3D camera view provides an approximate rendering of the map in three dimensions, in several different render modes: wireframe, flat shaded, textured, and fully lit by in-game light sources. While the 2D view is the main interface for creating and aligning level geometry, the 3D view is a vital tool for tasks such as texturing, or configuring light parameters.

Important The fully lit rendering mode in DarkRadiant is not identical to what the game engine will ultimately render. Certain advanced rendering features such as reflections and fog lights are not currently supported.

The 3D camera view provides its own toolbar which can be used to configure various display settings.

Render modes

wireframeMode16

Render in wireframe mode

Render objects as wire meshes.

solidMode16

Render in flat-shaded mode

Render objects as coloured solids, without textures or lighting.

textureMode16

Render in fullbright textured mode

Render objects as preview textures, with no lighting or material effects such as transparency.

lightingMode

Render in lighting preview mode

Render all available lighting and texture effects.

lightingModeWithShadows

Toggle shadow rendering

Enable the rendering of shadows when in lighting preview mode.

Animation rendering

StartPlayback

Start render time

Begin rendering animated effects.

StopPlayback

Stop render time

Stop rendering animated effects.

Far clip options

toggleFarClip

Toggle far clip

Enable or disable the far clip plane.

The far clip plane is a performance optimisation which avoids rendering geometry more than a certain distance away from the camera.

farClipIn

Clip plane in

Move the far clip plane closer to the camera.

farClipOut

Clip plane out

Move the far clip plane further away from the camera.

The 3D view always renders the scene from a particular camera position, which is shown in the 2D view as a blue diamond. This camera position can be set directly from the 2D view with Ctrl + Middle click, and the camera view direction can be set with Middle click. There are also various options within the 3D view itself to adjust the camera position.

Right click

Enter or leave free camera mode. In this mode, moving the mouse around updates the camera view direction in real-time, and moving the mouse around while holding Ctrl causes the camera to move up/down/left/right according to the camera motion.

Default mode (not free camera)

Left/Right arrow

Pan the camera left or right

Up/Down arrow

Move the camera forwards or backwards on the horizontal plane, without changing its height on the Z axis.

Free camera mode

Left/Right arrow

Move ("truck") camera left or right, leaving view direction the same.

Up/Down arrow

Move ("dolly") the camera forwards or backwards along its view axis

Manipulating objects

Every object in a map can be selected and moved within the 2D view. Some objects — including brushes, patches and lights — can also be resized.

For more advanced ways to select objects, see brush-based selection.

Shift + Left click

Select or deselect the object at the clicked position. Any existing selected objects will remain selected. If the clicked position overlaps more than one object, the closest one (according to the current 2D view axis) will be affected.

Alt + Shift + Left click

Select the object at the clicked position, and deselect any existing selected objects. If the clicked position overlaps more than one object, each click will cycle through the overlapping objects.

Shift + Left drag

Draw a selection rectangle, which will select any objects contained (fully or partially) within it.

ESC

Deselect all objects

Left drag (inside object)

Move the selected object(s)

Left drag (outside object)

Resize the selected object(s) (if available)

Space

Duplicate the selected object(s)

Backspace

Delete the selected object(s)

Tip Like other editors in the Radiant family, DarkRadiant offers a rather unusual system for resizing objects. Rather than clicking exactly on the edge, or on a dedicated resizing handle, you can click and drag anywhere outside an edge to move that edge inwards or outwards. Dragging outside a corner allows you to move two edges at once.

Flipping and rotating

DarkRadiant provides six buttons to quickly flip or rotate objects (in 90 degree increments) around each of the three world axes. These are available on the left-hand vertical toolbar.

brush flipx

Flip along the X axis

brush rotatex

Rotate around the X axis

brush flipy

Flip along the Y axis

brush rotatey

Rotate around the Y axis

brush flipz

Flip along the Z axis

brush rotatez

Rotate around the Z axis

Manipulator modes

For more precise control over object motion, there are three manipulator modes which can be selected with buttons on the left-hand vertical toolbar.

select mousetranslate

Translate mode

A manipulator widget with axis-aligned arrows will be displayed at the selected object’s center. Click and drag one of the arrows to move the object along that axis, or drag inside the manipulator box to move the object in two dimensions. This mode may be useful for moving brushes around without accidentally resizing them.

select mouserotate

Rotate mode

A widget with three axis-aligned rings will be displayed at the selected object’s center. Drag a ring to rotate the object by any arbitrary amount around that ring’s axis.

select mouseresize

Resize mode

This is the default Radiant drag mode (hence the "QE" icon referring to the original QERadiant) which allows you to move objects by dragging inside them and resize by dragging outside the boundary edges.

Working with brushes

Brushes are the basic building blocks of all maps. Typically they are used for coarse-grained level geometry such as walls, ceiling and floors. Brushes also have a vital role in sealing a map from the void: even a map built entirely from patches and static meshes must still be surrounded by brushes in order to avoid leaking.

Additive versus subtractive geometry

If you are used to mapping for the legacy Thief games using Dromed or T3Edit, the system used by DarkRadiant may seem somewhat back-to-front. In previous games, the world starts out as an infinite solid, in which you "carve out" rooms using subtractive brushes. In DarkRadiant, the world starts out as an infinite void, and all brushes are solid. The space in which the mission happens must be fully enclosed by solid brushes, otherwise the map will "leak" and fail to compile.

The need to deal with map leaks may at first seem like a burden, however the exclusive use of solid brushes frees the engine from needing to worry about "brush ordering", and allows an important performance optimisation: by "flood filling" the map interior, the map compiler can efficiently discard geometry that never needs to be rendered.

Creating a brush

To create a simple rectangular brush, ensure that nothing is selected (ESC), then Left drag in the 2D view. A new brush will be created and sized according to the dragged area, with its dimensions snapped to the current grid level. To adjust the third dimension of the brush (perpendicular to the view direction), used Ctrl + TAB to switch the 2D view axis, and Left drag outside the brush boundary to adjust the size.

Tip Whenever you drag to create a new brush, the third dimension will match the size of the most recently selected brush. This makes it easy to draw a series of brushes with the same height, such as when you need to create a series of floors or walls in succession. To match the height of an existing brush, simply select (Shift + Left click) and deselect it (ESC) before drawing the new brush.

More complex brush shapes

Although each brush starts out as a six-sided cuboid, it doesn’t have to stay that way. DarkRadiant offers several options for creating multi-sided brushes in more complex shapes. To create one of these shapes, first define a regular cuboid brush covering the volume you want the new shape to occupy, then choose the appropriate option from the Brush menu:

6Prism

Prism

An n-sided approximation of a cylinder, with the axis of the cylinder aligned with the current 2D view.

6Cone

Cone

A tapered n-sided cone, which always points upwards regardless of the 2D view axis.

6Sphere

Sphere

A rotationally symmetric n-sided approximation of a sphere, with the axis of rotation pointing upwards.

While these shapes can be useful for certain architectural modelling, remember that brushes are always flat-shaded and are not generally a good substitute for spheres or cones created with patches or static meshes.

Creating a room

Although it is not too difficult to create a hollow room by creating floor, ceiling and wall brushes manually, this is a common enough operation that DarkRadiant provides a couple of shortcuts. These options can be found on the vertical toolbar at the far left of the main window.

CreateRoomBrush

CreateRoom Create Room

Create a room whose interior size matches the size of the currently-selected brush. The wall thickness will be equal to the current grid size.

HollowBrush

Hollow Hollow

Hollow out the selected brush, leaving the exterior dimensions the same. The wall thickness will be equal to the current grid size, but the wall brushes will overlap at the corners, rather than just touching each other as with Create Room.

This is legacy tool from GtkRadiant, and generally inferior to Create Room. The overlapping wall brushes make it more difficult to precisely align interior textures, since part of the inner face is obscured (and therefore removed during map compilation). However, there may be occasional situations in which Hollow is useful, so it is retained in DarkRadiant.

The room creation tools do not require the initial brush to be rectangular — you can quite happily Create Room with a triangular or trapezoidal brush, or a brush with sloping sides. However, with a more complex brush shape, the complexity of the resulting wall geometry increases considerably, so attempting to hollow out a 7-sided sphere is probably ill-advised.

Splitting brushes

Sometimes it is necessary to divide a brush into two or more pieces, perhaps to create a doorway or other opening. The Clipper tool, accessed with the X key, is used for this purpose.

ClipTool3D
Figure 2. Splitting a brush into two parts
  1. Select the brush to be split (the Clipper can be activated with nothing selected, but it will not do anything useful).

  2. Press X to activate the Clipper, or click on the respective icon on the left-hand editing toolbar.

  3. Click in the 2D window at two different positions, to define the plane along which the brush will be split. The proposed split plane will be highlighted in blue; feel free to change 2D view axis with Ctrl + TAB or use the 3D camera view to better visualise the split plane.

  4. Once the split plane is defined, press Shift + Enter to execute the split and keep both halves of the brush; press Enter to execute the split and keep only one half. The part of the brush that is kept with Enter depends on the order in which you define the clip points: the points (marked 0 and 1) will appear clockwise on the brush edge according to the current 2D view. If in doubt, just use Shift + Enter to keep both parts, and delete the unwanted one afterwards.

  5. Repeat the process to perform additional splits on the selected brush, or disable the Clipper with the X key. The Clipper is a toggled tool and will remain active until disabled.

Note It is possible to create three split points before executing the split, which will define a split plane in three dimensions. Defining a three-point split plane which is actually useful, however, may be challenging.

Reshaping brush edges

All brush edges can be moved independently, which gives you the ability to quickly create shapes like triangles or trapeziums. This functionality is accessed via the Select Edges tool on the upper toolbar, or with the E key.

EdgeEditing
Figure 3. Creating a trapezium using edge editing
  1. Select a brush.

  2. Activate Select Edges with the toolbar button or E key. DarkRadiant will place a green control point at the center of each brush edge.

  3. In either the 2D or the 3D view, click and drag on a control point to move its edge. The control point will turn blue and move along with the cursor. In the 2D view, dragging corners is generally easiest, since the resulting shape change can more easily be seen.

  4. To reduce the number of brush sides, such as changing a rectangle into a triangle, simply drag one corner directly on top of another. The two edges will be merged.

Brush-based selection

As well as using brushes to define map geometry, you can also use them to select objects. There are three commands on the top toolbar which convert the selected brush(es) into a temporary selection volume:

SelectCompleteTall

Select complete tall

Select all objects that are completely contained within the two-dimensional outline of the selected brush(es) in the current 2D view window, ignoring their position on the third axis (perpendicular to the screen).

SelectInside

Select inside

Select all objects that are completely contained within the selected brush volume(s) in all three dimensions.

SelectTouching

Select touching

Select all objects that are touching the selected brushes. Unlike the previous two commands, this one does not remove the selected brushes, since it is designed to allow you to quickly select objects that are adjacent to real map geometry.

Working with patches

Patches are smooth-shaded Bezier surfaces that can be created and manipulated in the editor (unlike models), and used to represent a variety of curved shapes such as vaulted ceilings, arches or pillars. Patches are single-sided surfaces, not solid like brushes, and cannot be used to seal a map from the void — any patch work on the boundary of a map will need solid brushes behind it to prevent the map from leaking.

Creating a simple patch

A simple patch starts off as a flat rectangle, which can then be manipulated with vertex editing to produce a curved surface, if desired.

To create a simple patch:

  1. Set the 2D view axes (Ctrl + TAB) to define the orientation of the patch. The patch will be created facing directly towards the screen, so to create a horizontal (ceiling or floor) patch, the 2D view should be in XY (Top) orientation.

  2. Create a rectangular brush to define the width and height of the patch in the current 2D view (the third dimension is not important, since the patch will be infinitely thin once created).

  3. With the brush selected, choose Create Simple Patch Mesh from the Patch menu.

  4. In the dialog, choose the number of control points to define the shape of the patch along its width and height. A patch can have between 3 and 15 control points in each dimension; there will always be a control point at the extreme edge, and one in the middle. More control points allow more complex shapes but also require more manual adjustment — creating a simple arch is much easier with just three control points.

  5. Click OK to create the patch.

SimplePatchesControlPoints
Figure 4. Simple patches with 3, 7 and 15 control points in both dimensions

Manipulating control points

With a patch selected, press V to enter (or leave) vertex editing mode. This will display all of the control vertices, and allow you to select and move them.

  • Left click and drag a vertex to move just that one vertex.

  • Shift + Left click to add a vertex to the current selection set. When several vertices are selected, dragging any one of the selected vertices will move all of them together.

  • Shift + Left drag around several vertices to draw a selection rectangle that will toggle the selection state of all vertices inside it, selecting them if unselected and unselecting them if already selected.

PatchVertexEditing
Figure 5. Making an arch by raising the central row of vertices in a simple patch

Adding or removing control points

Control points can be added or removed from a patch using the appropriate sub-menus in the Patch menu.

Insert

Add rows or columns of control points without changing the dimensions of the patch — the control points will become more densely packed.

Extend

Add rows or columns of control points while extending the patch dimensions. The existing control points are left in the same position.

Delete

Remove rows or columns without changing the dimensions of the patch (the opposite of Insert). The control points will become less densely packed.

AddRemovePatchControlPoints
Figure 6. Inserting (top), Extending (middle) and Deleting (bottom) control points in a patch

Thickening a patch

When created, every patch has zero thickness and can only be viewed from one side; however, a patch can be made into an apparently solid object by creating additional patches automatically via the Thicken command in the Patch menu.

PatchThicken
Figure 7. Thickening a patch (left) with side walls (center) and no side walls (right)

The Thicken dialog presents several options:

Extrude along Vertex Normals

Thicken the patch by extruding the patch surface in the direction it is facing.

Extrude along X/Y/Z Axis

Thicken the patch by extruding the surface along the specified axis, ignoring the face normal direction.

Thickness (units)

Distance in map units to extrude the patch by.

Create seams ("side walls")

If checked, the extruded patch will be made into a fully solid "object" with an interior volume completely enclosed by patches. If unchecked, only the initial patch and its extruded copy will be created, with the sides left open.

Tip Although a thickened patch appears as a solid object, it still consists of individual patches which can be selected and manipulated individually. If you wish it to continue to behave as a solid, you can group the patches together.

More complex patch shapes

Just like with brushes, DarkRadiant offers several default patch shapes beyond the flat simple patch. These can be created by choosing the corresponding option in the Patch menu. There is no need to have a brush selected first in order to create these shapes, however if a brush is selected, it will be removed and used to define the size of the patch shape.

PatchSphere

Sphere

An approximation of a sphere (the quadratic Bezier patch implementation in Doom 3 and DarkRadiant does not permit the creation of a perfect sphere).

PatchCylinder

Cylinder

A hollow cylinder aligned with the direction of the 2D view.

PatchCone

Cone

A tapered cone pointing along the 2D view axis.

PatchEndCap

End cap

An arch or half-cylinder covering a 180 degree angle, aligned with the 2D view axis. The peak of the arch will be at the top if created in front or side views, making this useful for curved ceilings and the like.

PatchBevel

Bevel

Portion of an arch covering a 90 degree angle. This may be placed along room edges to give a curved appearance.

Controlling patch subdivision

Although patches are defined by Bezier curves, they are subdivided into flat polygons for rendering. By default, the number of polygons to create is determined dynamically by the game engine, based on the shape of the patch. However, you can also use the Patch Inspector to explicitly set the level of subdivision required, which can be useful when optimising a map by reducing on-screen polygon counts.

PatchSubdivision
Figure 8. Default (automatic) subdivision, 2x2 subdivision, 3x3 subdivision, 3x10 subdivision

To subdivide a patch:

  1. Select Patch Inspector in the View menu to make the inspector widget visible.

  2. With the patch selected, enable the Fixed Subdivisions checkbox.

  3. Use the Horizontal and Vertical numeric spinboxes to set the number of polygons to divide the patch into. The value can range from 1, making the patch completely flat regardless of control point positions, up to a maximum of 32. Each dimension can have a different subdivision level, if required.

Applying textures

When a brush or patch is created, it will be assigned a default texture. To apply a new texture, you must first select the brush, face or patch to be textured. There are two different selection commands:

Shift + Left click

Select an entire brush or patch. Any chosen texture will apply to all faces.

Ctrl + Shift + Left click

Select a single brush face for texturing. This command is only available in the 3D camera view

Once you have selected the objects or faces to texture, you can use either the Media or the Textures tab to perform the texturing operation.

The Media tab

The Media tab shows a tree view which contains all of the textures available in the game installation. Selecting a texture in the tree will show a small preview swatch, along with some metadata about the texture definition.

MediaTab

To apply a texture to the selected brush, simply Double-click on a texture name in the tree. The tree view also offers a context menu with several options:

Load in Textures view

Load all textures contained within the selected folder, making them available on the Textures tab. This option is not available when a single texture is highlighted.

Apply to selection

Apply the highlighted texture to the current object. This is identical to the Double-click operation, and is only available for single textures, not folders.

Show Shader Definition

Show a syntax-highlighted text window containing the definition of the selected texture.

Selected/deselect elements using this shader

Select or deselect objects in the map which the highlighted texture is applied to. This can be used for organisational purposes, or to identify whether a texture is used or not.

Add to/Remove from favourites

Add or remove the selected texture from the favourites list. The favourites list provides easy access to a user-chosen group of textures, and can be accessed by choosing the Show Favourites radio button at the top of the panel.

The Textures tab

The Textures tab provides a scrollable canvas containing preview swatches of all the textures which are currently loaded in the current map.

TexturesTab

When DarkRadiant first starts up no textures are loaded and this panel is empty. New textures can only be loaded via the Media tab (described in the previous section), either by applying a texture directly to a brush, or by using the Load in Textures view command to explicitly load an entire folder of textures.

Once textures are loaded onto the Textures tab, you can apply them to a selected object by Left clicking on them. By Right clicking on a texture you can access a context menu with a single command Seek in Media browser, which will highlight the clicked texture in the Media tab.

Using the Surface Inspector

Once a texture is applied via the Media or Textures tabs, you will most likely wish to adjust the alignment and scale of the texture on the brush or patch face. DarkRadiant provides the Surface Inspector for this purpose, which can be toggled with the S key or by choosing the option in the View menu.

SurfaceInspector

The Surface Inspector can be used to adjust textures on a single brush or patch face, or several selected faces/brushes/patches at once. If more than one face is selected and these faces have different values for text boxes in the dialog, the text box will be greyed out, however it is still possible to use the buttons to make changes which will be applied uniformly to all selected faces.

Shader

This shows the full name of the texture applied to the selected face(s). You can use the folder button to bring up a new dialog which allows you to choose a new texture.

Horiz/Vert Shift

These text boxes show the current texture shift (translation) on the horizontal and vertical axes. The associated arrow buttons will increase or decrease the texture shift by the current Step value.

Horiz/Vert Scale

These show the current texture scale in the horizontal and vertical directions. The arrow buttons will increase or decrease the scale by the current Step value.

Rotation

Shows the current texture rotation, in degrees. The arrow buttons will rotate the texture clockwise or anticlockwise by the current Step value.

Fit Texture

These controls allow you to fit an exact number of copies of the texture across the face, so that the texture edges correspond to the face edges.

The numeric spin boxes control how many copies of the texture are tiled on each axis. You can enter a value manually (including fractional values above or below 1.0) or use the spin buttons to quickly increase or decrease the number of tiles. Using the spin buttons will apply the fit immediately, so you can quickly preview the results in the camera view.

Toggle the preserveAspect button to preserve aspect ratio when using the spin buttons to fit the texture on one axis. This automatically adjusts the other axis so that the aspect ratio of the texture image is preserved, ignoring the value in the other axis' spin box. This can be useful for textures like wooden planks, where you might want an exact number of plank widths on a certain brush face but the number of lengths is not important (since the texture is seamless); in this case, avoiding aspect ratio distortion is more useful than fitting an exact number of lengths.

Align Texture

These buttons shift the texture so that the Top/Bottom/Left/Right edge of the face are aligned with a texture boundary, but otherwise do not modify the scaling of the texture (unlike the Fit operation).

Flip Texture

Flips (mirrors) the texture along the horizontal or vertical axis.

Natural

This button resets the texture to a default alignment and scale, based the location and size of the face.

Texture Lock

If this is enabled, the alignment of the texture will be preserved relative to the face if the brush or patch is moved in 3D space. If disabled, the texture itself will remain fixed in 3D space as the brush or patch moves, resulting in the alignment changing.

Typically, if you have Fit a particular number of texture tiles across a face, you will want to preserve alignment with Texture Lock. Conversely, if the texture is applied to a much larger group of brushes with a common texture (that needs to align across all of the brushes, regardless of how they are moved or resized), you will want to disable Texture Lock.

Using the shader clipboard

While constructing a map it will frequently be necessary to apply the same texture to several different surfaces such that they appear seamless in game. In order to assist with this, DarkRadiant provides a shader clipboard which allows shaders to be copied and pasted between primitives, and is independent of the main clipboard used for copying and pasting other objects.

Copying a shader

There are two ways to copy a shader to the shader clipboard.

  1. Select a single face (not an entire brush) with Ctrl + Shift + Left click in the 3D view, then choose Edit → Copy shader.

  2. Directly Middle click the face in the 3D view (there is no need to select it first).

In both cases, the ShaderClipboard section of the bottom status bar will update to show the new value of the shader clipboard. If the Media or Textures tab is visible, their contents will also update to view the selected shader.

Note Selecting a texture explicitly in the Media or Textures tabs will also update the shader clipboard with the selected shader.
Pasting a shader

Once a shader is on the shader clipboard, it can be pasted onto another surface in a number of ways:

  1. Select the destination face with Ctrl + Shift + Left click, then choose Edit → Paste shader or Edit → Paste shader (natural).

  2. Directly Middle click the destination face while holding down either Ctrl (to paste the shader with projected coordinates) or Shift (to paste the shader with natural coordinates).

Natural or projected pasting

The difference between natural and projected coordinates is apparent when pasting a shader onto a curved patch.

With projected coordinates (Ctrl + Middle click) the texture on the patch will be aligned identically to the texture on the source face, which might result in a stretched texture depending on the angle between the patch and the source face.

With natural coordinates (Shift + Middle click) the texture will flow over the curved surface in a more natural manner.

When pasting a shader onto a flat brush face, there may be little or no difference between the two options.

Working with entities

If brushes are the bricks and mortar of a map (often literally), entities are its fixtures and fittings. Every object in a map which "does something" other than form part of the level geometry is an entity: lights, audio speakers, particle emitters, static meshes, animated creatures or machinery. There are also various functional entity types which provide vital metadata to the game engine, such as determining where the player should start, or how creatures should navigate between locations.

DarkRadiant provides certain common functionality to all entities, such as the ability to edit properties using the Entity tab. Particular entity types are sufficiently common, however, that they have their own dedicated creation and editing tools.

Light

Every map requires at least one light source in order to render anything in game. A light occupies a rectangular volume, which can be created and resized much like a brush, and has properties to determine its colour, visible shape and falloff pattern in three dimensions. Lights can optionally cast shadows, and can even be animated to flicker or flash.

Model (func_static)

Model entities represent geometry that is not compiled as part of the map itself. The model geometry can either be derived from brushes and patches created inside DarkRadiant, or from an external model file in ASE or LWO format. Model files are the primary mechanism for including fine detail in a map which would be cumbersome to create with brushes and patches.

Speaker

Essentially the audio equivalent of a light, a speaker entity represents the point from which an in-game sound source will emanate. It has properties to control its size and falloff, and optionally override certain properties of the sound shader itself, such as volume.

Player start (info_player_start)

This entity tells the game engine where to place the player when a map is first loaded. A map without such an entity will not be playable.

Creating lights

To create a light, Right click in the 2D view and choose Create light…. The position and size of the light volume depends on the current selection:

  • If nothing is selected, then a light volume will be created at the clicked position with a default size.

  • If a single brush is selected, the brush will be deleted and the light volume will match the size and position of the brush.

  • If several brushes are selected, then all selected brushes will be deleted and the light volume will be sized according to the bounding box of the brushes (i.e. the smallest box that would contain all of the brushes).

Unselected lights are shown in the 2D view as small boxes, while selected lights also show the boundaries of the light volume.

LightSelectedAndUnselected
Figure 9. Light entity selected (left) and unselected (right)

A selected light entity can be moved by dragging inside the small center box, and it can be resized by dragging outside the edge of the light volume. Unlike brushes, light volumes will by default resize symmetrically, so that the center point does not move during the resize.

Note Although light volumes can be resized like brushes, their shape can never be changed; every light is an axis-aligned cuboid. This does not, however, mean that they need to look rectangular in game. See the next section for details on how to change the falloff texture using the light inspector.

There are a couple of options on the top toolbar which control the display and behaviour of light volumes:

view show lightradii

Show all light volumes

If enabled, light volume boundaries will be rendered in the 2D view for all light entities, not just selected entities. The default behaviour is to show only the center box for unselected light entities.

dragresize symm

Drag-resize entities symmetrically

If enabled (the default), light entities will be resized symmetrically, without moving the center point. If disabled, lights will be resized like brushes: dragging an edge will move only that edge, while the opposite edge remains fixed.

The light inspector

When initially created, a light is pure white in colour and has an unrealistic rectangular illumination pattern matching its shape. You can change these properties using the light inspector, which is accessed with the L key.

LightInspector
Tip The light inspector can change the properties of a single light, or multiple selected lights simultaneously.
Light volume (omni vs projected)

The majority of lights in a map will be the default, omnidirectional shape. An omni light is a simple cuboid which emits light in all directions from its center to its edges.

A projected light is pyramid-shaped, and emits light from the tip of the pyramid towards the base. Projected lights behave more like spotlights in real-life, and can be used to highlight particular areas or project images of windows onto the floor.

Colour

Use the colour selector button to display a standard colour selection dialog. As well as changing the hue, the light colour also governs the overall brightness of the light. You can use the slider below the colour button to adjust the brightness of the selected light(s) without changing the hue, with realtime feedback displayed in the 3D camera view if lighting preview mode is enabled.

Texture

The falloff texture controls the shape of the lit area when rendered in-game; the square texture chosen here will be mapped directly onto the rectangular shape of the light volume. Light textures can be simple, such as the generic circular gradient of biground1, or much more complex, including multiple colours or animation.

Options

There are a few light-propagation options which are mostly used to tweak performance. In particular, disabling shadows for any light which does not actually need to cast shadows can give a significant boost to rendering speed.

Creating models

Static models can be used to provide fine details in a map which would be difficult or impossible to create in the editor with brushes or patches. Models are created with an external 3D application such as Blender, Lightwave or Maya, and saved into the game asset tree in LWO or ASE format.

To insert a model, ensure that nothing is selected, then Right click in the 2D view and choose Create model…. DarkRadiant will show the model selector dialog:

ModelSelector

In the top-left of the model selector window is a tree of all available models in the game installation. Models may have different skins, which are variants of the same model with different textures applied. If a model has skins available, these will be listed as children of the model entry in the tree.

Choosing a model or one of its skins will show a preview render in the large widget on the right-hand side. Various metadata such as the polygon count and the applied textures are also shown in table at the lower left.

When you have chosen the desired model, click OK to insert it into the map. The model will be inserted at the position where you originally right-clicked to show the model chooser.

Creating a player start marker

The game requires a special entity (info_player_start) to mark the position at which the player should enter the map. Without such an entity the map will be unplayable.

To create this entity, ensure that nothing is selected then Right click in the 2D view and choose Create player start here. DarkRadiant will create the player start entity at the clicked position.

Since it makes no sense to have more than one player start location, DarkRadiant will not enable the Create player start here menu option if there is already an info_player_start in the map. Instead, you may choose Move player start here to move the existing entity to the clicked position.

Creating other entity types

Entity types without a dedicated item in the right-click menu are created using the generic Create entity… option, which displays a dialog very similar to the model selector:

EntityClassSelector

Just like the model selector, the entity selector displays a tree of all available entity types in the game installation, and a large preview widget which shows an approximate rendering of the entity, if appropriate. Purely functional entity types such as info_location or info_player_start do not have any visible appearance and their render preview will be blank.

Some entity types have a short textual description giving information about their usage; if present, this is displayed in the text box underneath the entity class tree.

After selecting the desired entity type in the tree, click the Add button to insert an instance of the entity into the map at the right-clicked location. If the selected entity type requires a brush selection and no brush is selected, a warning will be shown at this point.

Editing entity properties

Every entity has a list of key/value pairs known as properties or spawnargs. These properties are displayed on the Entity tab of the editing panel.

EntityInspector

The entity panel lists all of the properties of the currently-selected entity, showing each property’s name, its current value, and an icon representing its type (boolean, vector, text etc) if known. Selecting a property will populate the two text boxes in the center of the widget with the property name and value, allowing the value to be edited. If the selected property is of a known type, the panel at the bottom will show a custom widget appropriate for editing the particular property, e.g. three separate numeric spinboxes for a vector property, a colour selector widget for a colour property, and so on.

Changing a property value

To change the value of the selected property, simply enter the new value in the lower text box, then hit Enter or click the green tick button. If the property has a type-specific editing widget, you can also change its value using the controls in this widget.

Adding a new property

There are two different ways to add a new property:

  1. Enter a new property name in the upper text box (which shows the selected property name), and hit Enter. This does not rename the selected property, but adds a new property with the edited name and the current value.

  2. Right click in the list of properties and choose Add property from the context menu. This will display a new dialog listing all known properties along with their descriptive text (if available). Selecting a property in this dialog and choosing OK will add the property to the entity with a default value of "-", which can then be edited in the entity panel itself.

Deleting a property

To delete the selected property, Right click on the property in the list and choose Delete property.

The entity panel provides two options controlling its behaviour:

Show inherited properties

If checked, all properties that apply to the selected entity will be shown, including those which are inherited from the entity type declaration in the game installation. If unchecked, only those properties explicitly set on this particular entity (and stored in the map file) will be shown.

You can change the value of an inherited property by selecting it and entering a new value in the entity panel; this will create a new explicit property on the entity which overrides the inherited default.

Show help

Enables or disables the text widget at the bottom of the panel which shows a brief explanation of certain properties. If a property has help text available, the question mark icon will be shown in the ? column.

Reparenting primitives

Whenever a new brush or patch is created, it will automatically be made a child of the special worldspawn entity, which serves as the default entity containing all of the primitives which define the world geometry. However, worldspawn is not the only entity which can contain brushes and patches as children.

When you create a model using the model selector, DarkRadiant will insert a type of entity called a func_static into the map to represent the model geometry. A func_static can contain a model file loaded from disk in LWO or ASE format, but it can also be used as a parent for one or more primitives created within DarkRadiant. In either case, the behaviour of func_static is the same: it represents a static mesh which is rendered in game but is considered separate from the main world geometry, meaning that it does not participate in map compilation, will not seal the map from leaks, and will not cause intersecting brushes to be subdivided.

It is therefore often useful to make certain brushes and patches — typically those which represent "fine detail" rather than entire walls, floors and the like — into func_static entities to improve in-game performance and reduce the chances for map compilation problems caused by excessively complex world geometry.

The func_static entity class is not the only type of entity which can contain primitives: there are several other func_ entities which perform various functions, for example func_rotating which allows geometry to rotate continuously. DarkRadiant offers dedicated commands to convert to/from a func_static since this is a very common operation, however the ability to select, add and remove individual primitives behaves the same for all types of primitive-containing entity.

Converting primitives into func_static

To convert one or more existing primitives into a func_static entity, simply select all of the primitives, right-click in the 2D window, and choose Convert to func_static.

Manipulating individual child primitives

After converting a primitive, a number of changes are noticeable:

  1. The primitive may be drawn in a different colour.

  2. The primitive will no longer be resizeable by dragging its boundary with the mouse.

  3. When the primitive is selected, the Entity Inspector will no longer show the worldspawn entity, but a new entity with a different classname (e.g. func_static). You can set spawnargs on this entity like any other (including giving it a custom name).

  4. Selecting any contained primitive will cause a small X/Y/Z axis widget to be drawn at the entity’s origin position (which may be inside one of the primitives, or outside all of them, depending on their layout).

  5. If there are multiple primitives contained within a single entity, selecting any individual primitive will cause all of the entity’s primitives to be selected. This allows you to easily move the entire static object by simply dragging any one of its primitives.

However, it is still possible to perform operations on a single primitive, for example resizing a brush, by selecting it with the TAB key. Each press of TAB will cause DarkRadiant to select a different primitive contained within the entity, after which it will return to selecting the entire entity. With only a single primitive selected, all of the normal operations are possible on that primitive, for example deleting or resizing it.

The entity inspector widget makes it clear whether you have selected an entity or a primitive within that entity, using the text above the list of entity properties. If an entire entity is selected, the text will appear similar to Entity 1, whereas with a primitive selected it will read Entity 1, Primitive 1.

Adding or removing primitives

Once you have created a func_static or similar entity from a number of primitives, you can add or remove primitives without needing to create a new entity from scratch.

Adding a primitive

Select the entity, then expand the selection (i.e. using Shift + Left click) to include one or more existing primitives to add to this entity. Then choose Edit → Reparent primitives.

Removing a primitive

Use the TAB key to select the individual primitive to remove (you must do this even if there is only one primitive in the entity), then choose Edit → Reparent primitives to worldspawn. The removed primitive will still exist in the map but it will be a regular worldspawn brush or patch, not parented to any other entity.

Unparenting all primitives

With the entity selected, simply right-click in the 2D view and choose Revert to worldspawn to turn all of the primitives back into worldspawn.

Compiling a map

DarkRadiant does not include functionality for compiling a map into the form needed by the game engine; instead, you must use external tools or the map compiler built into the game itself.

For Doom 3 and the Dark Mod, the following commands are used within the in-game console (which can normally be accessed with the key immediately above TAB):

dmap <mymapname.map>

Compile the map called mymapname.map, which must be located within the maps directory of the mod installation. If there are any problems compiling the map (e.g. a leak), the error will be displayed in the console output.

map <mymapname.map>

Load the compiled map mymapname.map into the game engine and start playing it immediately.

Tip When compiling and testing maps, it may be helpful to set your game to play in windowed mode, with a reduced resolution. This will allow both the game and DarkRadiant to be visible on the screen as separate windows, which you can easily switch between during the compile and test cycle.

Preventing leaks

A map "leak" occurs when the play area is not fully enclosed with a complete shell of opaque brushes. If the map leaks, compilation will fail and the map will not be playable.

In order to minimise the likelihood of a map leak, ensure that your map has all of the following properties:

  • The map interior is completely sealed from the exterior void by brushes (not patches). It is much easier to achieve this by building up a map carefully, making good use of the grid snapping functionality, rather than haphazardly throwing brushes together and hoping to seal them later.

  • All of the sealing brushes have an opaque texture. Skybox textures are considered opaque and are OK, however semi-transparent or perforated mesh textures are not.

  • The origin point of every entity in the map lies within the sealed map interior. It is OK if a large model extends outside of the map, provided that its origin point is on the inside.

Warning Do not be tempted to avoid leaks by enclosing your entire map in a single huge box. This may seem to solve the problem (the map will indeed not leak), but it completely negates the important performance optimisations that the map compiler carries out when it "flood fills" the map interior.

Locating leaks with a pointfile

No matter how hard you try to avoid leaks, occasionally they will happen. In this case the pointfile functionality is helpful to identify the location of the leak.

After the map compilation has failed with a leak, return to DarkRadiant and choose Pointfile from the File menu. This will automatically load the point file associated with the current map, which contains a series of points identifying the path to the leak. This path will be rendered as a bright red line in both the 2D and 3D views:

Pointfile
Figure 10. A pointfile rendered in both 3D and 3D views

In this example we can clearly see that the map has leaked because the far wall brush does not join up with the ceiling.

Organising a map

Since a fully developed Dark Mod map is large and complex, DarkRadiant provides several tools to make organising a large map easier. Objects can be grouped, sorted into user-defined layers and filtered using various criteria, while the prefab system allows large chunks of map to be reused or shared with other mappers.

Grouping objects

DarkRadiant allows a number of objects to be grouped together, so that they can be selected and manipulated as a single unit.

To create a group:

  1. Select several objects.

  2. Right-click in the 2D window to show the context menu.

  3. Choose Group Selection.

Once the objects are in a group, selecting any object in the group will automatically select all other objects in the same group.

To remove a group, select the group then choose Ungroup Selection from the 2D view context menu.

Note Groups can be nested, by creating a group that includes one or more existing groups. When you ungroup such a nested group, the original component groups will be restored.

Working with prefabs

DarkRadiant allows a collection of objects to be saved to disk as a prefab, which can then be imported into other maps. You can use prefabs to store anything from a single small object to a vast section of map geometry complete with lights and AI.

Exporting to a prefab

  1. Select the objects in the map that you wish to include in the prefab.

  2. From the File menu, choose Save selected as prefab…​

  3. Use the file chooser dialog to choose a location and name for the prefab file.

Tip Unlike actual .map files which must be accessible by the game engine, prefabs are a DarkRadiant-only feature that have no significance to the engine. You are therefore free to store prefab files wherever you wish, either inside or outside the game installation directory.

Importing a prefab

Either right-click in the 2D window and choose Insert prefab…​, or open the File menu and choose Import prefab…​. This will show the prefab browser.

PrefabChooser

Like the model selector, the prefab selector shows a tree of available prefabs on the left, and a preview window on the right giving an idea of what the prefab looks like. Using the radio buttons at the top of the window, you can choose whether to browse prefabs contained within the game installation, or within a custom directory of your choice.

The preview window functions much like the 3D view in the main application: right click to enter or leave camera mode, which enables the following motion commands:

Mouse move

Change the camera view direction (pan or tilt)

Mouse wheel

Zoom the camera

Up/Down arrow

Move the camera forwards or backwards

Left/Right arrow

Move the camera left or right

When you have chosen the desired prefab, click OK to insert it into the map. Before inserting the prefab, you can use the Create Group out of Prefab parts checkbox to control whether the prefab is automatically grouped as a single object, or inserted as separate selectable objects.

Exporting models

DarkRadiant provides a limited ability to export scene geometry into a number of 3D model file formats: ASCII Scene Export (ASE), Lightwave (LWO) or Wavefront OBJ. This functionality is provided to help with organising frequently-used map elements — DarkRadiant is not intended to compete with full-featured 3D modelling applications such as Blender or 3DS Max.

Exporting to a model is similar to exporting to a prefab, except that models can only contain geometry (brushes or patches), not other map entities such as lights or speakers. However, unlike prefabs, models can be edited with other 3D software, and exporting map geometry as a model might provide a useful template for creating map-specific static meshes in a more powerful modelling tool.

To export a model:

  1. Select the geometry to be exported. Note that DarkRadiant currently does not complain if you select non-geometry such as lights, however these will not appear in the resulting model file.

  2. Open the File menu and choose Export selected as model…​

  3. In the Output Format dropdown, choose one of the supported model formats: ASCII Scene Export (.ase), Lightwave Object File (.lwo), or Wavefront OBJ (.obj).

  4. Choose the path for the exported model file in the File Path entry box.

  5. Click OK to export the model.

Using layers

When a map contains a large number of objects, it may become difficult to work with the 2D views as a result of the visual clutter. Organising the map into several layers can help solve this problem. The visibility of each layer can toggled independently, allowing you to focus on the objects you want to work with.

Layers do not impose any requirements on the physical layout of objects: it is possible to include objects spread all over a map into a single layer. For example, you can have a layer for all enemies, another layer for all lights, another layer for brushwork, and so on.

The Layers window

To show or hide the Layers window, choose Layers from the Edit menu. The window lists all of the layers which exist in the current project, and allows you to perform various operations on them.

LayersWindow
Creating a layer

To create a new layer, click the New button at the bottom of the window. A popup will be shown asking for the name of the new layer. Once the layer is created, it will appear in the list.

Deleting a layer

Click the red 'X' button to the right of a layer to delete it. Deleting a layer does not delete the objects in the layer, only the layer itself. Any objects in that layer will be moved to the default layer.

Renaming a layer

Click the edit button to the right of a layer name to change the name. A popup will be shown asking for the new name.

Selecting objects on a layer

Click on the name of a layer itself to select all objects on that layer.

Toggling visibility

The button to the left of a layer name is used to toggle the visibility of objects on that layer. If objects are visible, a tick is shown in the button, otherwise it is empty.

Changing the active layer

The visibility toggle button shows a star for the layer which is currently set as the active layer. To change the active layer, Ctrl + Left click on the layer you wish to set as the new active layer.

Moving objects into layers

An object can be placed in any number of layers. To see which layers a selected object is in, look at the narrow coloured rectangle next to the layer name in the Layers window. The rectangle will turn from grey to pink for each layer that contains the selected object.

LightInTwoLayers
Figure 11. A light in two layers: "Default" and "Lights"

All newly-created objects will be placed in the Default layer. You can move or copy objects between layers using the options in the 2D view’s context menu.

Create layer…​

Bring up the name entry dialog and create a new layer, exactly as if the New button in the Layers window had been clicked.

Add to layer…​

Copy the selected object into the chosen layer, without removing it from its existing layer(s).

Move to layer…​

Move the selected object into the chosen layer, removing it from all other layers.

Remove from layer…​

Remove the selected object from the chosen layer.

Filtering map elements

While the Layers feature allows maps to be organised into manual groupings of objects, DarkRadiant also provides a mechanism for controlling the visibility of items based on their characteristics. This is controlled via the Filter menu.

Built-in filters

The Filter menu is populated with a number of built-in filter rules which are expected to be useful to mappers. Each filter may be activated independently, and each activated filter will be shown with a tick alongside its name. Filters operate in a "subtractive" sense: if a filter is active, objects matched by that filter will be hidden; the remaining visible objects will be those which are not matched by any active filters.

Tip Active filters are persisted into settings, and are therefore retained between DarkRadiant sessions.

The built-in filters include:

All entities

Hide all entities other than the worldspawn, leaving only brushes and patches visible.

World geometry

The inverse of All entities. Hides brushes and patches while leaving entities visible.

Brushes

Hide only brushes, leaving patches and entities visible.

Patches

Hide only patches, leaving brushes and entities visible.

Caulk

Hide any brush or patch which has the caulk texture applied to at least one surface.

Collision surfaces

Hide the additional collision meshes which are embedded in certain models, while leaving the models themselves visible. This filter is especially useful because collision meshes often obscure parts of the model itself.

Aside from the list of filters, the Filter menu contains three other options:

Activate all filters

Activate every filter in the list. Very unlikely to be useful, because it will probably result in every object in the map becoming invisible.

Deactivate all filters

Turn off all active filters. This one is useful, since you may have manually activated a number of filters and want to turn them all off at once.

Edit filters…​

Display a dialog allowing you to create, edit and manage the list of available filters.

Customising filters

In addition to the filters supplied with the mod distribution, DarkRadiant also allows you to add your own custom filters to the list by choosing the Edit Filters…​ menu option. This displays a dialog containing the list of all available filters, including built-in ones. Use the Add and Delete buttons to add or remove custom filters from the list, and the Edit button to enter a new dialog which allows you to edit the rules of the selected filter.

Built-in filters cannot be removed or edited, but you can choose the View button to open the filter editor in a read-only mode.

FilterEditor
Figure 12. The filter editor dialog

Each filter consists of a number of rules, which are applied in the order shown in the list box. Filters may contain only a single rule ("hide all speaker entities"), or multiple rules ("hide all entities, then show only speaker entities"). You can freely add, remove or reorder rules using the buttons to the right of the rules list.

Each rule has the following components:

Index

An integer representing the rule’s position in the list, numbered from zero.

Type

This controls what the rule is "looking for" when it tries to match objects to hide or show. Currently there are four rule types: entityclass which matches the classname of entities (e.g. "speaker"), object which matches either "brush" or "patch" and is used for controlling the visibility of map geometry, texture which matches the name of an applied texture, and entitykeyvalue which matches the value of a specific property on the entity.

Entity Key

This column is only used for entitykeyvalue rules, in which case it contains the name of the property to match (while the value to match will be contained in the Match column).

Match

This contains the actual value to be matched by the rule. Its interpretation and allowed values will depend on the rule type. For object type rules the value must be "brush" or "patch", whereas with all other rule types the value may be any arbitrary string.

Action

Choose whether this rule will result in matched objects being shown, or hidden. The filter system starts with everything being visible by default, so a filter which does not contain at least one hide rule will have no effect.

The entity list

As a map becomes larger and more complex, keeping track of its contents may become more challenging. To assist with this, DarkRadiant provides an Entity List which functions as an "outline" view of the map, listing all entities and their child brushes and patches (if any).

The entity list can be accessed by choosing the Entity List option from the View menu.

EntityList
Figure 13. The entity list, showing a number of entities in a small test map

The tree structure shown in the entity list corresponds to the structure of the map itself: a single "world" entity which acts as the parent of the brushes and patches in the map, alongside a number of other entities that have been placed by the mapper, some of which may contain their own child brushes or patches.

Clicking on an entity in the list will cause it to be selected in the map. If the Focus camera on selected entity checkbox is enabled, the camera will additionally be moved to view the clicked entity.

By enabling the List visible nodes only checkbox, you can limit the entity list to show only entities which are not currently hidden via filters.

Dark Mod features

The Dark Mod is a considerably more complex game than vanilla Doom 3, and its maps therefore include certain settings and features that would be cumbersome to configure manually by entering property values on entities. DarkRadiant therefore provides a number of Dark Mod specific dialogs which are described in this section.

Note Most Dark Mod features are compiled as separate plugins, and may not be built by default on certain platforms. If these features seem to be missing, contact the distributor of your DarkRadiant binary package for advice, or examine the build options if you are compiling DarkRadiant yourself from source code.

The Difficulty editor

Most Dark Mod maps can be played on one of three possible difficulty settings, typically named "Easy", "Medium" and "Difficult" (although these names can be overridden). The precise effects of each of these difficulty settings are fully under the control of the map author, and might include such effects as spawning or despawning particular enemies, changing enemy health or patrol routes, or modifying the details of objectives.

DarkRadiant provides a Difficulty editor dialog to facilitate one particular class of difficulty-dependent modification: making global changes to entity classes throughout the map. This could be used, for example, to change the health of every instance of a particular enemy, or (as shown in the diagram) removing a particular enemy type’s ability to relight torches.

DifficultyEditor
Figure 14. The Difficulty editor, showing a modified property on a particular entity class

The Difficulty editor shows the names of the available difficulty levels in a dropdown widget, beneath which are the settings for the selected difficulty level. The difficulty names are customisable on a per-map basis — normally these will be the default values of "Easy", "Medium" and "Difficult", but if the current map has customised difficulty names DarkRadiant will adjust the tab names accordingly.

On the left is a tree view showing all of the property overrides for the current difficulty level. Each top-level item is a particular entity class, which contains all of the property changes that are made to this entity class in this difficulty level. In this example, the ai_builder_guard entity has its canLightTorches property set to 0 on the Easy difficulty setting, meaning that all enemies of this particular type will not be able to relight torches.

Adding a setting

To add a new property setting for the current difficulty level, click the Add button. The widgets on the right hand side will become available, allowing you to choose an entity class, a property ("Spawnarg") to change, and the change to make ("Argument"). You can choose a number of mathematical operations for the modification, including a simple value assignment, or an addition or multiplication. After specifying the values, make sure you click the Save button to commit the changes into the list view.

Removing a setting

Select an item in the list view and click the Delete button to remove a particular setting. You can only remove individual assignments from the list; to remove all of the assignments for a particular entity class, you must select and delete each one individually.

Editing the difficulty name

To edit the name of the current difficulty level, click the edit button to the right of the dropdown, and enter a new name in the text box. The modified name will be written into a property on the worldspawn entity and reflected both in game and in DarkRadiant.

Tip For details of more advanced difficulty-dependent changes, such as modifying the behaviour of a single entity (rather than an entire entity class), consult the Dark Mod Wiki.

Game Connection

The Dark Mod includes functionality to dynamically interact with a DarkRadiant session running on the same machine, allowing certain information (such as camera position) to be synchronised both to and from the game, and for certain entity property changes to be pushed to the running game without needing to restart.

These features are accessed in DarkRadiant through the Connection menu and buttons on the camera view toolbar.

Activating the connection

  1. In The Dark Mod, load the map which you are currently editing in DarkRadiant.

  2. Bring down the game console and enter the command

    com_automation 1

    This should result in a status message indicating that the game is listening for connections on a particular network port.

    Automation now listens on port 3879

The game process is now ready to exchange data with DarkRadiant.

Synchronising camera position

You can synchronise the DarkRadiant camera position and the game player position in both directions: editor to game and game to editor. This feature is most easily controlled with the buttons on the camera view toolbar, but it can also be activated from the Connection menu.

CameraSync

Game position follows DarkRadiant camera

Any motion of the DarkRadiant camera will be transmitted in realtime to the game, resulting in the player position moving (in noclip mode) to the same position and view direction.

This is a toggled option which remains active until switched off.

CameraSyncBack

Move camera to current game position

Update the DarkRadiant camera to match the current player position and view direction in game.

This is a single-shot command; there is no mechanism to continuously move the DarkRadiant camera in response to player motion in game.

Command reference

File menu

New map

Prompt to save and close the current map (if necessary), then start working on a new empty map.

Open map…​

Prompt to save and close the current map (if necessary), then display a file browser to choose and load an existing map file from disk.

Import map…​

Display a file browser to choose and load an existing map file from disk, merging the contents with the existing map

Import prefab…​

Display the prefab browser to choose and import a prefab from disk.

Note Importing a map and importing a prefab are functionally identical operations; the only difference is the user interface used for choosing what to import. The prefab browser is designed to offer a user-friendly workflow for browsing, previewing and importing from a library of frequently-used map elements, while Import map may be more useful for merging two or more partially-complete maps.
Save

Save the current map to disk under its existing file name.

Save as…​

Display a file browser to choose a new name for the current map, then save to this new file name in future.

Save copy as…​

Display a file browser to choose a new filename to save this map into, without changing the current map name for future Save operations.

Save selected as Map…​

Choose a file name and save the currently-selected items into a new map file without changing the current map name. Equivalent to Save copy as but it only saves the selected items, not the entire map.

Save selected as prefab…​

Equivalent to Save selected as Map but it saves the selected items into a prefab (*.pfb) file in the standard prefab location.

Save selected as Collision Model…​

Allows a selected map object (typically a brush) to be set as the collision model for a particular ASE or LWO model. After choosing this option, DarkRadiant will display the model chooser dialog, allowing you to choose the particular model that the selected object should be associated with. The selected brush is then saved, and associated with the model so that subsequent insertions of the same model will use the new collision geometry.

Reload Models/Selected Models/Skins/Scripts/Readable Guis/Materials/Defs/Particles

Forces DarkRadiant to re-read the selected category of items from disk, refreshing its internal data structures. This is necessary if you have edited or re-exported some asset which DarkRadiant is using in the current map and you want to see the latest changes.

Game/Project Setup…​

Show the Game Setup dialog for configuring game-specific settings.

Pointfile

Load and show the pointfile for the current map, if there is one. If more than pointfile is available, a dialog will be shown allowing you to choose which pointfile to load. An error dialog will be displayed if there is no current pointfile (which is usually the case if the current map has not leaked during compilation). Choose this option a second time to hide the rendered pointfile.

Exit

Exit DarkRadiant, prompting to save the current map if necessary.

Edit menu

Undo

Undo the most recent operation.

Redo

Redo the most recently undone operation.

Copy

Copy the selected item(s) to the clipboard.

Paste

Paste the item(s) on the clipboard to their original world location.

Note Objects copied to the clipboard are represented using the same text format which can be found in .map files. This makes it possible to save clipboard content into a file and load it later as an actual map fragment.
Paste to camera

Paste the item(s) on the clipboard to the current camera location, ignoring their original world location.

Duplicate

Make a copy of the currently selected item(s), slightly offset from their original position.

Delete

Remove the currently selected item(s).

Group selection

Combine the selected items into a group.

Ungroup selection

Split the selected group back into individual objects.

Reparent primitives

Make all selected worldspawn brushes or patches into children of the selected func_static (or similar entity). Requires exactly one entity to be selected, along with at least one primitive which is currently a child of the worldspawn.

Reparent primitives to worldspawn

Unparent the selected primitive from a func_static (or similar entity), making it a child of the worldspawn. Before using this command you must first select a single primitive with the TAB key (even if the entity only contains a single primitive), otherwise the whole entity will be selected and the command will silently fail.

Tip To unparent all of an entity’s primitives and convert them back into worldspawn, just right-click in the 2D view and choose Revert to worldspawn.
Merge selected entities

Convert two more more selected entities into a single entity which contains all of the contained brushes and patches. Only works for entities which can contain primitives (e.g. func_static).

Copy shader

Copy the shader from the selected face to the shader clipboard.

Paste shader

Paste the shader currently on the shader clipboard to all selected faces.

Clear selection

De-select all selected objects.

Invert selection

De-select all selected objects, and select all unselected objects.

Select complete tall

Convert the currently-selected brush into a selection volume, selecting all objects which are completely contained within its outline in the current 2D view (ignoring the third dimension). See brush-based selection.

Select inside

Convert the currently-selected brush into a selection volume, selecting all objects which are completely contained within it in all three dimensions. See brush-based selection.

Select fully inside

Like Select inside, except that contained brushes which touch the boundary of the selection brush will not be selected.

Select children

Select primitives which are children of the currently-selected entity. See reparenting primitives.

Select parent entities

Select the parent entity of the currently-selected primitive. See reparenting primitives.

View menu

New XY view

Create a new dockable orthographic (2D) view.

New Camera view

Create a new dockable 3D camera view.

Colours…​

Show a dialog for choosing and editing colour schemes.

Entity menu

Connect selected entities

Set a target spawnarg on the first selected entity pointing to the second selected entity.

Bind selected entities

Set a bind spawnarg on the first selected entity pointing to the *second selected entity.

Entity class tree…​

Show a tree of all available entity types in the current game, along with all of their properties. Unlike the tree shown in the Create Entity dialog, this entity class tree shows an inheritance-based hierarchy and does not include a 3D preview.

Brush menu

Prism…​

Create an angular prism (extruded polygon) from the selected brush. See brush shapes.

Cone…​

Create a cone or pyramid from the selected brush. See brush shapes.

Sphere…​

Create an approximation of a sphere from the selected brush. See brush shapes.

CSG → Make Hollow

Create a hollow room from the selected brush. See creating a room.

CSG → Make Room

Create a hollow room from the selected brush, without any overlapping walls. See creating a room.

Clipper → Clip Selection

Split the selected brush along the defined clip plane, keeping one half. See splitting brushes.

Clipper → Split Selection

Split the selected brush along the defined clip plane, keeping both halves. See splitting brushes.

Clipper → Flip Clip Orientation

Change which half of the brush is retained after using the Clip Selection command. Difficult to use in practice; instead just Split Selection and delete the unwanted half manually. See splitting brushes.

Make Detail / Make Structural

These options only exist to support legacy games, and are not used in the Dark Mod.

Configuring DarkRadiant

DarkRadiant offers a large number of configurable options which can be used to tailor its behaviour to your desired workflow. Most of these options can be found either in the Preferences dialog or exposed directly as menu items.

The Preferences dialog

The Preferences dialog can be shown by choosing Preferences…​ from the Edit menu. The dialog contains a number of pages containing groups of logically related options.

Camera settings

The Camera page contains options relating to the movement and behaviour of the 3D camera.

Movement Speed

Use this slider to control how many game units the camera moves forwards or backwards when you use the scroll wheel in the 3D view. It does not affect the speed of rotation or lateral dragging (e.g. with Ctrl) in free look mode, nor does it affect motion with the arrow keys.

Rotation Speed

This controls the speed of angular rotation when dragging the mouse after entering free look mode with right-click. If you have a high DPI mouse and want to be able to direct the camera more precisely, reducing this setting may help.

Freelook mode can be toggled

Disabling this checkbox makes the free look functionality behave more like typical MMO games, where you hold down the right mouse button and drag to move the camera around. Uncheck this option if you hate modal interfaces or find the default toggle behaviour confusing.

Discrete movement (non-freelook mode)

If this is checked, moving the camera with the arrow keys in non-freelook mode will cause discrete jumps in position, rather than smooth motion.

Enable far clip plane

You can completely disable the far clip plane by unchecking this option. This will avoid the need to manage the position of the far clip plane, but may negatively impact rendering performance in large or complex maps.

Note Technically it is not actually possible to disable the far clip plane, since having a far clip plane is a requirement for 3D rendering to work correctly. This command in fact sets the far clip plane to a very high value, e.g. 32768. If your map is very large, it is conceivable that you will still see some far clipping behaviour.
Invert mouse vertical axis

Enable this option to flip the sense of the vertical camera motion when freelook mode is enabled, so that moving the mouse upwards tilts the camera downwards, and vice versa.

Solid selection boxes

This option controls whether selected brushes are drawn with a dashed outline (option disabled) or a solid line (option enabled). It affects both the 2D and the 3D views.

Show camera toolbar

Uncheck this to completely hide the toolbar at the top of the 3D camera window (which includes the render mode buttons and the far clip plane controls).

Orthoview settings

The Orthoview page contains options controlling the display and behaviour of the 2D views.

View chases mouse cursor during drags

If this is enabled, dragging an object off the edge of a 2D view will cause the 2D view to automatically scroll to keep the dragged object in view. If disabled, the dragged object will reach the edge and stop. You can control the speed of the scrolling with the Maximum Chase Mouse Speed slider.

Update views on camera movement

This option controls whether the camera position indicator in the 2D views is automatically kept in sync with camera movements in the 3D window. If this option is disabled, the 2D view camera indicator may not move until you explicitly click on or interact with a 2D view.

Show crosshairs

Enable this option to display full-window-sized crosshairs tracking the mouse cursor whenever it moves over a 2D window. This may assist with precise selection or object alignment.

Show grid

Control the visibility of grid lines in the 2D views. This does not affect the snapping behaviour, just the visual rendering of the grid.

Show size info

Control the visibility of the text overlays which show the dimensions of a selected object on the X, Y or Z axes. This option is also available in the View → Show menu.

Show entity angle arrow

Hide or show the small arrow which indicates the direction of an entity with an angle spawnarg, such as info_player_start. This affects both the 2D and 3D views.

Show entity names

Enable this to show permanently-visible text names next to each entity in the map. This option is also available as View → Show → Show names.

Show blocks

If enabled, the world space is divided into a horizontal grid of 1024x1024 unit blocks (of infinite height) which are outlined in blue in the 2D views. Each block is assigned a pair of numbers representing its position from the centermost block, which is assigned (0, 0). This might help with "blocking out" a map at the beginning of the design phase. This option is also available in the View → Show menu.

Show coordinates

Toggle the visibility of the coordinate rulers along the edges of the 2D window. Also available in the View → Show menu.

Show axes

Control the visibility of the axis widget displayed at the top-left of each 2D window and at the world origin. Also available in the View → Show menu.

Show window outline

Enable this to draw a rectangular outline around the edge of the 2D window. Depending on the platform and GUI theme this may be almost invisible, but might be useful to improve visibility in certain environments.

Show workzone

The 'workzone' is an imaginary axis-aligned cuboid which encloses the set of currently-selected items (this is what defines the volume of a new light, when a light is created from one or more existing brushes). Enabling this option causes the workzone to be outlined in red in the 2D views. Also available in the View → Show menu.

Translate manipulator always constrained to axis

This option affects the behaviour of the translate manipulator. When the option is disabled, dragging a selected object in translation mode will behave as if the manipulator’s central square is being dragged, and allow motion in two dimensions. If the option is enabled, dragging the selected object will behave as if the closest manipulator arrow is being dragged, and allow motion along only a single axis. Translation in two dimensions will always be possible by clicking on the manipulator’s central square directly, regardless of the state of this option.

Higher selection priority for entities

When using the mouse to click on and select an entity which is in front of, behind or inside a brush, this option controls whether DarkRadiant will prefer to select the entity (enabled) or the brush (disabled).

Multi Monitor settings

The Multi Monitor page contains a single setting, Start DarkRadiant on monitor, which allows you to choose which monitor DarkRadiant will start on if you have several available.

Autosave settings

Enable Autosave

Controls whether the autosave feature is active or disabled.

Autosave Interval

Use this slider to choose how often DarkRadiant will make an autosave. By default, autosaves are made every 5 minutes.

Save Snapshots

If this option is enabled, DarkRadiant will make each autosave into a separate copy of the map file, allowing you to potentially revert changes which were made several autosaves ago. If this option is disabled, there will only ever be a single autosave file, which will protect against DarkRadiant or system crashes but not against long-term erroneous changes.

Snapshot folder

This specifies the name of the folder used to store snapshot autosaves, if the Save Snapshots option is enabled.

Max Snapshot size per map

This allows you to control the amount of disk space used for storing snapshots, by specifying a maximum number of megabytes that will be used for storing the snapshots for a single map. If the disk usage grows above this limit, DarkRadiant will start to delete old snapshots.

Clipper settings

Clipper tool uses caulk texture

If this option is enabled, the clipper tool will texture the newly-created clip face with the texture specified in the Caulk shader name text field. If the option is disabled, the new face will be given the same texture as the rest of the brush.

Grid settings

This page contains a couple of options relating to the appearance and default behaviour of the grid.

Default grid size

Use this combo box to choose the default grid size used in new projects (to change the grid size in the current project, use the options in the Grid main menu).

Major grid style

Choose the rendering style for the major grid lines. Available options are Lines, Dotted Lines, More Dotted Lines, Crosses, Dots, Big Dots, and Squares.

Minor grid style

Choose the rendering style for the minor grid lines. Available options are the same as the Major grid style combo box.

Selection settings

Ignore light volume bounds when calculating default rotation pivot location

This option affects the behaviour of the rotation tool when multiple objects are selected. DarkRadiant will place the rotation widget at the approximate "center of gravity" of the set of selected objects. If this option is enabled, any selected lights will be treated as point entities, with no volume in 3D space regardless of their actual light volumes. If this option is disabled, the entire light volume will be taken into account as if the light were a rectangular brush.

Undo settings

Undo Queue Size

Use this spinbox to control the number of operations which are saved onto DarkRadiant’s internal undo stack. Larger values provide a longer history of undoable operations, at the expense of requiring more memory.

Primitives settings

This page contains two options controlling the default behaviour of applied textures. These values can be set on a per-object basis using the Surface Inspector.

Default texture scale

Set a default scale factor for newly applied textures.

Enable texture lock

Set the default value of the Texture Lock button. See the Surface Inspector section for more details on this feature.

Texture Browser settings

These options control the behaviour of the Textures tab.

Uniform texture thumbnail size

Choose the size in pixels that will be used for texture thumbnails.

Texture scrollbar

Hide or show the scrollbar in the textures tab. If the scrollbar is hidden, scrolling is only possible with the mouse wheel.

Mousewheel increment

This option determines how much the window is scrolled when the mouse wheel is rotated.

Max shadername length

Choose the maximum number of characters that may appear in each texture name. If a texture contains more characters than this, the texture name will be abbreviated with "…​" in the middle.

Map files settings

Number of most recently used files

Choose the number of map files to list in the recent map section at the bottom of the File menu.

Open last map on startup

Enable this option to make DarkRadiant automatically load the most recently-used map every time it starts, rather than starting with an empty map.

Features for game distributors

DarkRadiant is designed to work out of the box with a standard Doom 3 or Dark Mod game installation, however it also offers a few features aimed at developers of the game itself.

Controlling asset visibility

As the development of a game progresses, certain models or textures may become obsolete or deprecated, either because they are no longer needed or because they fall short of the quality standard that is expected of new assets. If these models and textures have already been distributed, removing them from the game installation may be problematic, as maps which depend on them will fail to load correctly.

DarkRadiant offers a mechanism to deal with this by allowing certain assets to be marked as "hidden". A hidden asset will no longer be presented for selection by the user (e.g. on the Media tab or in the Model selector), but will continue to function as normal when it appears in a loaded map.

Creating an assets.lst file

To change the visibility of assets, you need to create a file called assets.lst which resides in the top-level models or materials directories in the mod installation. This file may be inside a PK4 or in an extracted directory tree.

The contents of assets.lst are a simple list of key/value pairs, assigning a visibility value to each named asset. For example:

assets.lst
darkmod/chairs/some_broken_chair.lwo=hidden
darkmod/tables/another_table.ase=hidden

Asset paths listed on the left-hand side are interpreted relative to the directory containing assets.lst (which must be models or materials). The visibility value on the right-hand side must be either hidden or normal; a value of normal is equivalent to not listing the file at all, and results in no change to its visibility.

Note Only files may be listed in an assets.lst, not items in a virtual hierarchy such as the material shader tree. When an MTR file is listed as hidden in the materials directory, all shaders contained within it will be hidden in DarkRadiant. This means that in order to hide specific shaders, you must move these into one or more MTR files which are listed as hidden.
================================================ FILE: include/Bounded.h ================================================ #ifndef BOUNDED_H_ #define BOUNDED_H_ #include /* FOWARD DECLS */ class AABB; /// Interface for bounded objects, which have a local AABB. class Bounded { public: virtual ~Bounded() {} /// Return the local AABB for this object. virtual AABB localAABB() const = 0; }; typedef std::shared_ptr BoundedPtr; #endif /*BOUNDED_H_*/ ================================================ FILE: include/GLProgramAttributes.h ================================================ #pragma once namespace render { /** * Enumeration for vertex attributes to be bound to a GLProgram, to avoid using * magic numbers. */ struct GLProgramAttribute { enum Index { Position = 0, TexCoord = 8, Tangent = 9, Bitangent = 10, Normal = 11, Colour = 12, }; }; } ================================================ FILE: include/Rotatable.h ================================================ #pragma once #include "math/Quaternion.h" /// Interface for an object which can be rotated class Rotatable { public: virtual ~Rotatable() {} /// Rotate the object by the given Quaternion virtual void rotate(const Quaternion& rotation) = 0; }; ================================================ FILE: include/Scalable.h ================================================ #pragma once #include "math/Vector3.h" /// Interface for an object which can be scaled class Scalable { public: virtual ~Scalable() {} /// Scale the object by the given vector virtual void scale(const Vector3& scaling) = 0; }; ================================================ FILE: include/StringSerialisable.h ================================================ #pragma once #include #include /** * \brief * Interface for an object which can serialise itself to/from a string. */ class StringSerialisable { public: /** * \brief * Destructor */ virtual ~StringSerialisable() {} /** * \brief * Export this object's state to a string. */ virtual std::string exportToString() const = 0; /** * \brief * Import this object's state from a given string. */ virtual void importFromString(const std::string& str) = 0; }; typedef std::shared_ptr StringSerialisablePtr; ================================================ FILE: include/Texture.h ================================================ #pragma once #include #include #include /** * \brief * Basic interface for all GL textures. * * This interface represents a texture which is bound to OpenGL, with an OpenGL * texture number (as returned from glGenTextures()). This may be a 2D, 3D, cube * map or any other kind of texture object supported by OpenGL. */ class Texture { public: /** * \brief * Destructor */ virtual ~Texture() {} /** * \brief * Constant indicating an invalid texture size. */ const static std::size_t INVALID_SIZE = 0; /** * \brief * Return the string name of this texture. */ virtual std::string getName() const = 0; /** * \brief * Return the GL texture identifier for this texture. */ virtual GLuint getGLTexNum() const = 0; /** * \brief * Return the width of this texture in pixels. May return INVALID_SIZE if * this texture does not have a valid size. */ virtual std::size_t getWidth() const = 0; /** * \brief * Return the height of this texture in pixels. May return INVALID_SIZE if * this texture does not have a valid size. */ virtual std::size_t getHeight() const = 0; }; typedef std::shared_ptr TexturePtr; ================================================ FILE: include/Translatable.h ================================================ #pragma once #include "math/Vector3.h" /// Interface for an object which can be translated class Translatable { public: virtual ~Translatable() {} /// Translate this object by the given vector virtual void translate(const Vector3& translation) = 0; }; ================================================ FILE: include/VolumeIntersectionValue.h ================================================ #pragma once /** * \brief * Enumeration of possible intersection results between two volumes. */ enum VolumeIntersectionValue { VOLUME_OUTSIDE, VOLUME_INSIDE, VOLUME_PARTIAL }; ================================================ FILE: include/editable.h ================================================ #pragma once class AABB; #include "inode.h" class Snappable { public: virtual ~Snappable() {} virtual void snapto(float snap) = 0; }; typedef std::shared_ptr SnappablePtr; inline SnappablePtr Node_getSnappable(const scene::INodePtr& node) { return std::dynamic_pointer_cast(node); } class ComponentEditable { public: virtual ~ComponentEditable() {} virtual const AABB& getSelectedComponentsBounds() const = 0; }; typedef std::shared_ptr ComponentEditablePtr; inline ComponentEditablePtr Node_getComponentEditable(const scene::INodePtr& node) { return std::dynamic_pointer_cast(node); } class ComponentSnappable { public: virtual ~ComponentSnappable() {} virtual void snapComponents(float snap) = 0; }; typedef std::shared_ptr ComponentSnappablePtr; inline ComponentSnappablePtr Node_getComponentSnappable(const scene::INodePtr& node) { return std::dynamic_pointer_cast(node); } ================================================ FILE: include/i18n.h ================================================ #pragma once #include #include "imodule.h" #include "iradiant.h" namespace language { class ILocalisationProvider { public: virtual ~ILocalisationProvider() {} typedef std::shared_ptr Ptr; // Returns the localised version of the given string virtual std::string getLocalisedString(const char* stringToLocalise) = 0; }; class ILanguageManager { public: virtual ~ILanguageManager() {} /** * Registers the given provider, which will be used to resolve localised strings. */ virtual void registerProvider(const ILocalisationProvider::Ptr& instance) = 0; /** * Removes references to the localisation provider. */ virtual void clearProvider() = 0; /** * Returns the localised version of the given input string * or the unmodified string if no suitable localisation provider * was found. */ virtual std::string getLocalisedString(const char* stringToLocalise) = 0; }; } // This is the accessor for the global language manager module inline language::ILanguageManager& GlobalLanguageManager() { return GlobalRadiantCore().getLanguageManager(); } #define GETTEXT_PACKAGE "darkradiant" // Redefine the _() macro to return a std::string for convenience #ifndef WXINTL_NO_GETTEXT_MACRO #define WXINTL_NO_GETTEXT_MACRO #endif // Custom translation macros _, N_ and C_ inline std::string _(const char* s) { if (!module::IsGlobalModuleRegistryAvailable()) { return s; // it's still too early for this call, return the unmodified string } if (!module::GlobalModuleRegistry().moduleExists(MODULE_RADIANT_CORE)) { return s; // still too early } return GlobalLanguageManager().getLocalisedString(s); } // Macro used to decorate a string as localizable, such that it is recognised // by the xgettext parser, but without triggering an actual function call // at the place it is used. Can be used to e.g. decorate constants in the code. #define N_(str) str #ifndef C_ #define C_(context,text) _(text) #endif ================================================ FILE: include/iaasfile.h ================================================ #pragma once #include #include "imodule.h" #include #include "math/Plane3.h" #include "math/Vector3.h" #include "math/AABB.h" namespace map { // An AAS type is defined by an entityDef block // Each AAS type has its own file extension struct AasType { std::string entityDefName; std::string fileExtension; }; typedef std::list AasTypeList; /** * Representation of a Area Awareness System file. * Provides read-only access to Area and Portal information. * Use the GlobalAasFileManager() to acquire an instance of * this class. */ class IAasFile { public: virtual std::size_t getNumPlanes() const = 0; virtual const Plane3& getPlane(std::size_t planeNum) const = 0; virtual std::size_t getNumVertices() const = 0; virtual const Vector3& getVertex(std::size_t vertexNum) const = 0; // An edge references two vertices by index struct Edge { int vertexNumber[2]; }; virtual std::size_t getNumEdges() const = 0; virtual const Edge& getEdge(std::size_t index) const = 0; virtual std::size_t getNumEdgeIndexes() const = 0; virtual int getEdgeByIndex(int edgeIdx) const = 0; struct Face { int planeNum; // number of the plane this face is on unsigned short flags; // face flags int numEdges; // number of edges in the boundary of the face int firstEdge; // first edge in the edge index short areas[2]; // area at the front and back of this face }; virtual std::size_t getNumFaces() const = 0; virtual const Face& getFace(int faceIndex) const = 0; virtual std::size_t getNumFaceIndexes() const = 0; virtual int getFaceByIndex(int faceIdx) const = 0; struct Area { int numFaces; // number of faces used for the boundary of the area int firstFace; // first face in the face index used for the boundary of the area AABB bounds; // bounds of the area Vector3 center; // center of the area an AI can move towards unsigned short flags; // several area flags unsigned short contents; // contents of the area short cluster; // cluster the area belongs to, if negative it's a portal short clusterAreaNum; // number of the area in the cluster int travelFlags; // travel flags for traveling through this area }; virtual std::size_t getNumAreas() const = 0; virtual const Area& getArea(int areaNum) const = 0; }; typedef std::shared_ptr IAasFilePtr; /** * A loader class capable of constructing an IAasFile instance from a token stream. */ class IAasFileLoader : public RegisterableModule { public: /** * Get the display name of this AAS file loader, e.g. "Doom 3", "Quake 4", etc. */ virtual const std::string& getAasFormatName() const = 0; /** * Each MapFormat can have a certain game type it is designed for, * a value which conincides with the type attribute in the game tag * found in the .game file, e.g. "doom3" or "quake4". */ virtual const std::string& getGameType() const = 0; /** * greebo: Returns true if this loader is able to parse * the contents of this file. Usually this includes a version * check of the file header. */ virtual bool canLoad(std::istream& stream) const = 0; /** * Load the AAS file contents from the given stream. */ virtual IAasFilePtr loadFromStream(std::istream& stream) = 0; }; typedef std::shared_ptr IAasFileLoaderPtr; // Info structure representing a single AAS file on disk struct AasFileInfo { std::string absolutePath; AasType type; }; class IAasFileManager : public RegisterableModule { public: virtual ~IAasFileManager() {} // Register a loader which is considered by all future AAS file load attempts virtual void registerLoader(const IAasFileLoaderPtr& loader) = 0; // Unregister a previously registered loader instance virtual void unregisterLoader(const IAasFileLoaderPtr& loader) = 0; // Get a loader capable of loading the given stream virtual IAasFileLoaderPtr getLoaderForStream(std::istream& stream) = 0; // Get the list of valid AAS types virtual AasTypeList getAasTypes() = 0; // Returns a specific AAS type. Will throw a std::runtime_error if the // type is not valid. virtual AasType getAasTypeByName(const std::string& typeName) = 0; // Returns a list of AAS files for the given map (absolute) map path virtual std::list getAasFilesForMap(const std::string& mapPath) = 0; }; } // namespace const char* const MODULE_AASFILEMANAGER("ZAasFileManager"); // Application-wide Accessor to the global AAS file manager inline map::IAasFileManager& GlobalAasFileManager() { static module::InstanceReference _reference(MODULE_AASFILEMANAGER); return _reference; } ================================================ FILE: include/iarchive.h ================================================ #pragma once /** * \file iarchive.h * Types relating to the use of ZIP archives (PK4 files) and their contents. * \ingroup vfs */ #include "igameresource.h" #include "imodule.h" #include #include "itextstream.h" #include class InputStream; // Interface providing additional info about a given file // used by the FileInfo structure to load extended info // file like size, containing archive, physical path, etc. class IArchiveFileInfoProvider { public: virtual ~IArchiveFileInfoProvider() {} // Get file size of the file given by the relative path (like "def/func.def") in bytes virtual std::size_t getFileSize(const std::string& relativePath) = 0; // Returns true if this file is an actual file on disk (as opposed to a file in a PAK) virtual bool getIsPhysical(const std::string& relativePath) = 0; // Returns the absolute file system path to the archive the given file is located in virtual std::string getArchivePath(const std::string& relativePath) = 0; }; /** * A file opened in binary mode. * \ingroup vfs */ class ArchiveFile { public: /// \brief destructor virtual ~ArchiveFile() {} /// \brief Returns the size of the file data in bytes. virtual std::size_t size() const = 0; /// \brief Returns the path to this file (relative to the filesystem root) virtual const std::string& getName() const = 0; /// \brief Returns the stream associated with this file. /// Subsequent calls return the same stream. /// The stream may be read forwards until it is exhausted. /// The stream remains valid for the lifetime of the file. virtual InputStream& getInputStream() = 0; }; typedef std::shared_ptr ArchiveFilePtr; /** * A file opened in text mode. * \ingroup vfs */ class ArchiveTextFile : public game::IResource { public: /// \brief Returns the path to this file (relative to the filesystem root) virtual const std::string& getName() const = 0; /// \brief Returns the stream associated with this file. /// Subsequent calls return the same stream. /// The stream may be read forwards until it is exhausted. /// The stream remains valid for the lifetime of the file. virtual TextInputStream& getInputStream() = 0; }; typedef std::shared_ptr ArchiveTextFilePtr; /** * Representation of an archive in the virtual filesystem. * This might be a PK4/ZIP file or a regular mod directory. * * \ingroup vfs */ class IArchive : public IArchiveFileInfoProvider { public: typedef std::shared_ptr Ptr; virtual ~IArchive() {} class Visitor { public: virtual ~Visitor() {} // Invoked for each file in an Archive virtual void visitFile(const std::string& name, IArchiveFileInfoProvider& infoProvider) = 0; // Invoked for each directory in an Archive. Return true to skip the directory. virtual bool visitDirectory(const std::string& name, std::size_t depth) = 0; }; /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. /// Name comparisons are case-insensitive. virtual ArchiveFilePtr openFile(const std::string& name) = 0; /// \brief Returns a new object associated with the file identified by \p name, or 0 if the file cannot be opened. /// Name comparisons are case-insensitive. virtual ArchiveTextFilePtr openTextFile(const std::string& name) = 0; /// Returns true if the file identified by \p name can be opened. /// Name comparisons are case-insensitive. virtual bool containsFile(const std::string& name) = 0; /// \brief Performs a depth-first traversal of the archive tree starting at \p root. /// Traverses the entire tree if \p root is "". /// When a file is encountered, calls \c visitor.file passing the file name. /// When a directory is encountered, calls \c visitor.directory passing the directory name. /// Skips the directory if \c visitor.directory returned true. /// Root comparisons are case-insensitive. /// Names are mixed-case. virtual void traverse(Visitor& visitor, const std::string& root) = 0; }; ================================================ FILE: include/iarray.h ================================================ #pragma once namespace ui { enum class ArrayArrangement { Line = 0, Circle = 1, Spline = 2 }; enum class ArrayOffsetMethod { Fixed = 0, // Fixed world-space distance Relative = 1, // Relative to bounding box size Endpoint = 2 // Distribute between start and end points }; } // namespace ================================================ FILE: include/iautosaver.h ================================================ #pragma once #include "imodule.h" namespace map { /** * Public interface to to automatic map save algorithms. * * DarkRadiant can be configured to create map backups on demand, * which can be a simple copy of the current map that is overwritten every time, * or it can create sequential snapshots in a separate folder including size limitations. * * The configuration of the save behaviour is done through registry keys. */ class IAutomaticMapSaver : public RegisterableModule { public: virtual ~IAutomaticMapSaver() {} // Run the checks to see if the map needs to be automatically saved. // If the auto saver is not enabled, nothing happens. // Returns true if the map is ready to be auto-saved, false otherwise. virtual bool runAutosaveCheck() = 0; // Perform an automatic save, unconditionally. This will run the save algorithms // for the currently loaded map, regardless whether it is due for a save or not. // Call the "runAutosaveCheck" method to see if an autosave is overdue. virtual void performAutosave() = 0; }; constexpr const char* const RKEY_AUTOSAVE_SNAPSHOTS_ENABLED = "user/ui/map/autoSaveSnapshots"; constexpr const char* const RKEY_AUTOSAVE_SNAPSHOTS_FOLDER = "user/ui/map/snapshotFolder"; constexpr const char* const RKEY_AUTOSAVE_MAX_SNAPSHOT_FOLDER_SIZE = "user/ui/map/maxSnapshotFolderSize"; constexpr const char* const RKEY_AUTOSAVE_SNAPSHOT_FOLDER_SIZE_HISTORY = "user/ui/map/snapshotFolderSizeHistory"; } constexpr const char* const MODULE_AUTOSAVER("AutomaticMapSaver"); // Application-wide Accessor to the global map auto saver inline map::IAutomaticMapSaver& GlobalAutoSaver() { static module::InstanceReference _reference(MODULE_AUTOSAVER); return _reference; } ================================================ FILE: include/ibrush.h ================================================ #pragma once #include "inode.h" #include "imodule.h" #include "math/Vector2.h" #include "math/Vector3.h" #include "math/Matrix3.h" #include "math/Matrix4.h" #include class Plane3; const std::string RKEY_ENABLE_TEXTURE_LOCK("user/ui/brush/textureLock"); namespace brush { // Helper class hosting brush-related settings class IBrushSettings { public: virtual ~IBrushSettings() {} virtual const Vector3& getVertexColour() const = 0; virtual void setVertexColour(const Vector3& colour) = 0; virtual const Vector3& getSelectedVertexColour() const = 0; virtual void setSelectedVertexColour(const Vector3& colour) = 0; virtual sigc::signal& signal_settingsChanged() = 0; }; class BrushCreator : public RegisterableModule { public: virtual scene::INodePtr createBrush() = 0; virtual IBrushSettings& getSettings() = 0; }; enum class PrefabType : int { Cuboid = 0, Prism, Cone, Sphere, NumPrefabTypes, }; // Public constants const std::size_t c_brush_maxFaces = 1024; const std::size_t PRISM_MIN_SIDES = 3; const std::size_t PRISM_MAX_SIDES = c_brush_maxFaces - 2; const std::size_t CONE_MIN_SIDES = 3; const std::size_t CONE_MAX_SIDES = 32; const std::size_t SPHERE_MIN_SIDES = 3; const std::size_t SPHERE_MAX_SIDES = 7; } // The structure defining a single corner point of an IWinding struct WindingVertex { Vector3 vertex; // The 3D coordinates of the point Vector2 texcoord; // The UV coordinates Vector3 tangent; // The tangent Vector3 bitangent; // The bitangent Vector3 normal; // The normals std::size_t adjacent; // The index of the adjacent WindingVertex // greebo: This operator is needed to enable scripting support // using boost::python's vector_indexing_suite. bool operator==(const WindingVertex& other) const { return (vertex == other.vertex && texcoord == other.texcoord && tangent == other.tangent && bitangent == other.bitangent && normal == other.normal && adjacent == other.adjacent); } }; // A Winding consists of several connected WindingVertex objects, // each of which holding information about a single corner point. typedef std::vector IWinding; /** * greebo: The texture definition structure containing the scale, * rotation and shift values of an applied texture. * At some places this is referred to as "fake" texture coordinates. * This is not what is actually saved to the .map file, but it makes * texture manipulations in the Surface Inspector much more human-readable. */ struct ShiftScaleRotation { double shift[2]; double rotate; double scale[2]; ShiftScaleRotation() { shift[0] = shift[1] = 0; rotate = 0; scale[0] = scale[1] = 1; } }; class IBrush; // Interface for a face plane class IFace { public: // Destructor virtual ~IFace() {} // Returns a reference to the brush containing this face virtual IBrush& getBrush() = 0; // Submits the current state to the UndoSystem, to make further actions undo-able virtual void undoSave() = 0; // Returns true if the texture of this face is not filtered out // This doesn't take into account whether the owning brush is visible or not virtual bool isVisible() const = 0; // Shader accessors virtual const std::string& getShader() const = 0; virtual void setShader(const std::string& name) = 0; // Shifts the texture by the given s,t amount in texture space virtual void shiftTexdef(float s, float t) = 0; // Convenience wrapper to shift the assigned texture by the given amount of pixels // the passed values are scaled accordingly and passed on to shiftTexdef() virtual void shiftTexdefByPixels(float s, float t) = 0; // Scales the tex def by the given factors in texture space virtual void scaleTexdef(float s, float t) = 0; // Rotates the texture by the given angle virtual void rotateTexdef(float angle) = 0; // Returns the amount of texture pixels per game unit shown on this face // This is based on the image returned by the material, usually the editor image virtual Vector2 getTexelScale() const = 0; // Returns the texture aspect ratio width/height virtual float getTextureAspectRatio() const = 0; // Fits the texture on this face virtual void fitTexture(float s_repeat, float t_repeat) = 0; // Flips the texture by the given flipAxis (0 == x-axis, 1 == y-axis) virtual void flipTexture(unsigned int flipAxis) = 0; // This translates the texture as much towards the origin in texture space as possible without changing the world appearance. virtual void normaliseTexture() = 0; enum class AlignEdge { Top, Bottom, Left, Right, }; // If possible, aligns the assigned texture at the given anchor edge virtual void alignTexture(AlignEdge alignType) = 0; // Reverts any transform that has been applied since the last time freezeTransform() was called virtual void revertTransform() = 0; // Promotes the current transformed state to the new base state virtual void freezeTransform() = 0; // Get access to the actual Winding object virtual IWinding& getWinding() = 0; virtual const IWinding& getWinding() const = 0; virtual const Plane3& getPlane3() const = 0; /** * The matrix used to project world coordinates to U/V space, after the winding vertices * have been transformed to this face's axis base system. * The components of this matrix correspond to the matrix values written to the idTech4 * brushDef3 face definition (with holding the translation part): * e.g. ( plane ) ( ( xx yx zx ) ( yx yy zy ) ) "textures/path/to/material" 0 0 0 */ virtual Matrix3 getProjectionMatrix() const = 0; virtual void setProjectionMatrix(const Matrix3& projection) = 0; // Constructs the texture projection matrix from the given (world) vertex and texture coords. // Three vertices and their UV coordinates are enough to construct the texdef. virtual void setTexDefFromPoints(const Vector3 points[3], const Vector2 uvs[3]) = 0; /** * Calculates and returns the texture definition as shift/scale/rotate. * This is not what is actually saved to the .map file, but it makes * texture manipulations in the Surface Inspector much more human-readable. */ virtual ShiftScaleRotation getShiftScaleRotation() const = 0; virtual void setShiftScaleRotation(const ShiftScaleRotation& scr) = 0; // Transforms this face plane with the given transformation matrix virtual void transform(const Matrix4& transformation) = 0; // Emitted from this IFace's destructor, as last sign of life virtual sigc::signal& signal_faceDestroyed() = 0; }; // Plane classification info used by splitting and CSG algorithms struct BrushSplitType { std::size_t counts[3]; BrushSplitType() { counts[0] = 0; counts[1] = 0; counts[2] = 0; } BrushSplitType& operator+=(const BrushSplitType& other) { counts[0] += other.counts[0]; counts[1] += other.counts[1]; counts[2] += other.counts[2]; return *this; } }; // Brush Interface class IBrush { public: virtual ~IBrush() {} // Returns the number of faces for this brush virtual std::size_t getNumFaces() const = 0; // Get a reference to the face by index in [0..getNumFaces). virtual IFace& getFace(std::size_t index) = 0; // Const variant of the above virtual const IFace& getFace(std::size_t index) const = 0; // Add a new face to this brush, using the given plane object, returns a reference to the new face virtual IFace& addFace(const Plane3& plane) = 0; // Add a new face to this brush, using the given plane, projection matrix and material name virtual IFace& addFace(const Plane3& plane, const Matrix3& textureProjection, const std::string& material) = 0; // Removes all faces from this brush virtual void clear() = 0; // Returns true when this brush has no faces virtual bool empty() const = 0; // Returns true if any face of the brush contributes to the final B-Rep. virtual bool hasContributingFaces() const = 0; // Remove any faces from this brush that are not contributing anything to the resulting polyehdron // These are planes that have the same normal as an existing face and are superceded by them // This method is meant to be used during map loading to remove redundancy parsed from legacy maps virtual void removeRedundantFaces() = 0; // Removes faces that do not contribute to the brush. // This is useful for cleaning up after CSG operations on the brush. // Note: removal of empty faces is not performed during direct brush manipulations, // because it would make a manipulation irreversible if it created an empty face. virtual void removeEmptyFaces() = 0; // Sets the shader of all faces to the given name virtual void setShader(const std::string& newShader) = 0; // Returns TRUE if any of the faces has the given shader virtual bool hasShader(const std::string& name) = 0; // Returns TRUE if any of the brush's faces has a visible material, FALSE if all faces are effectively hidden virtual bool hasVisibleMaterial() const = 0; /** * greebo: This is used by the filter system (for example) to trigger * an update of the cached visibility flags. This enables a brush * to quickly cull its hidden faces without issuing lots of internal calls. */ virtual void updateFaceVisibility() = 0; // Saves the current state to the undo stack. // Call this before manipulating the brush to make your action undo-able. virtual void undoSave() = 0; enum DetailFlag { Structural = 0, Detail = 1 << 27, // 134217728 }; /** * Q3-compatibility feature, get the value of the detail/structural flag */ virtual DetailFlag getDetailFlag() const = 0; /** * Q3-compatibility feature, set the detail/structural flag */ virtual void setDetailFlag(DetailFlag newValue) = 0; // Classify this brush against the given plane, used by clipper and CSG algorithms virtual BrushSplitType classifyPlane(const Plane3& plane) const = 0; // Method used internally to recalculate the brush windings virtual void evaluateBRep() const = 0; }; // Forward-declare the Brush object, only accessible from main binary class Brush; class IBrushNode { public: virtual ~IBrushNode() {} /** greebo: Retrieves the contained Brush from the BrushNode */ virtual Brush& getBrush() = 0; // Returns the IBrush interface virtual IBrush& getIBrush() = 0; }; typedef std::shared_ptr IBrushNodePtr; inline bool Node_isBrush(const scene::INodePtr& node) { return node->getNodeType() == scene::INode::Type::Brush; //return std::dynamic_pointer_cast(node) != NULL; } // Casts the node onto a BrushNode and returns the Brush pointer inline Brush* Node_getBrush(const scene::INodePtr& node) { IBrushNodePtr brushNode = std::dynamic_pointer_cast(node); if (brushNode != NULL) { return &brushNode->getBrush(); } return NULL; } // Casts the node onto a BrushNode and returns the IBrush pointer inline IBrush* Node_getIBrush(const scene::INodePtr& node) { IBrushNodePtr brushNode = std::dynamic_pointer_cast(node); if (brushNode != NULL) { return &brushNode->getIBrush(); } return NULL; } const char* const MODULE_BRUSHCREATOR("Doom3BrushCreator"); inline brush::BrushCreator& GlobalBrushCreator() { static module::InstanceReference _reference(MODULE_BRUSHCREATOR); return _reference; } ================================================ FILE: include/icameraview.h ================================================ #pragma once #include "imodule.h" #include "iinteractiveview.h" #include "irenderview.h" templateclass BasicVector3; typedef BasicVector3 Vector3; class Matrix4; namespace camera { enum { CAMERA_PITCH = 0, // up / down CAMERA_YAW = 1, // left / right CAMERA_ROLL = 2, // fall over }; // Abstract class used when handling mouse events // see also: class IOrthoView in iorthoview.h class ICameraView : public virtual IInteractiveView { public: typedef std::shared_ptr Ptr; virtual ~ICameraView() {} // Sets the device width and height, updates the projection virtual void setDeviceDimensions(int width, int height) = 0; // Move the camera's origin virtual const Vector3& getCameraOrigin() const = 0; virtual void setCameraOrigin(const Vector3& newOrigin) = 0; virtual const Vector3& getCameraAngles() const = 0; virtual void setCameraAngles(const Vector3& newAngles) = 0; // Combined setter for position and angles - triggers only one callback to potential observers virtual void setOriginAndAngles(const Vector3& newOrigin, const Vector3& newAngles) = 0; // Returns the vector pointing to the "right" virtual const Vector3& getRightVector() const = 0; // Returns the vector pointing "up" virtual const Vector3& getUpVector() const = 0; // Returns the vector pointing "forward" virtual const Vector3& getForwardVector() const = 0; virtual const Matrix4& getModelView() const = 0; virtual const Matrix4& getProjection() const = 0; // Cubic clipping virtual float getFarClipPlaneDistance() const = 0; virtual void setFarClipPlaneDistance(float distance) = 0; virtual bool getFarClipPlaneEnabled() const = 0; virtual void setFarClipPlaneEnabled(bool enabled) = 0; }; class IFreeMoveView : public virtual IInteractiveView { public: virtual ~IFreeMoveView() {} // Freemove mode virtual void enableFreeMove() = 0; virtual void disableFreeMove() = 0; virtual bool freeMoveEnabled() const = 0; }; class ICameraViewManager : public RegisterableModule { public: virtual ~ICameraViewManager() {} // Create a new camera instance. The ICameraViewManager is keeping a reference to this // object for broadcasting the focusCamera() calls, so be sure to notify the manager // if this camera is no longer in use by invoking destroyCamera(). // The requestRedraw takes a bool indicating whether the redraw should be queued (false) // or a redraw should be forced (true) virtual ICameraView::Ptr createCamera(render::IRenderView& view, const std::function& requestRedraw) = 0; // Releases this camera instance, clearing any internal references to it virtual void destroyCamera(const ICameraView::Ptr& camera) = 0; // Sets the position and angles of all active cameras to the given values virtual void focusAllCameras(const Vector3& position, const Vector3& angles) = 0; // A reference to the currently active view. Will throw a std::runtime_error if no camera is present virtual ICameraView& getActiveView() = 0; // Signal emitted when any camera position or angles changed virtual sigc::signal& signal_cameraChanged() = 0; }; } constexpr const char* const MODULE_CAMERA_MANAGER("CameraManager"); constexpr const char* const RKEY_CAMERA_DRAG_SELECTION_ENABLED = "user/ui/camera/dragSelectionEnabled"; // Module accessor inline camera::ICameraViewManager& GlobalCameraManager() { static module::InstanceReference _reference(MODULE_CAMERA_MANAGER); return _reference; } ================================================ FILE: include/iclipboard.h ================================================ #pragma once #include #include "imodule.h" namespace radiant { /** * Interface to DarkRadiant's clipboard which is able to * store and retrieve a string from and to the system clipboard. * Access it through the GlobalClipboard() function. * * This module might not be present in all configurations * so its advisable to check for its presence first. */ class IClipboard : public RegisterableModule { public: virtual ~IClipboard() {} /// Return the contents of the clipboard as a string virtual std::string getString() = 0; /// Copy the given string to the system clipboard virtual void setString(const std::string& str) = 0; // A signal that is emitted when the contents of the system clipboard changes virtual sigc::signal& signal_clipboardContentChanged() = 0; }; } const char* const MODULE_CLIPBOARD("Clipboard"); inline radiant::IClipboard& GlobalClipboard() { static module::InstanceReference _reference(MODULE_CLIPBOARD); return _reference; } ================================================ FILE: include/iclipper.h ================================================ #pragma once #include "imodule.h" #include "iorthoview.h" #include "math/Vector3.h" #include "math/Plane3.h" // The possible split modes enum EBrushSplit { eFront, eBack, eFrontAndBack, }; enum PlaneClassification { ePlaneFront = 0, ePlaneBack = 1, ePlaneOn = 2, }; class ClipPoint; const char* const MODULE_CLIPPER("Clipper"); const char* const RKEY_CLIPPER_CAULK_SHADER("user/ui/clipper/caulkTexture"); /* greebo: This is the interface the clipper module has to provide. */ class IClipper : public RegisterableModule { public: // Gets called if the clip mode is toggled on/off virtual void onClipMode(bool enabled) = 0; // Returns true if the clip mode is enabled virtual bool clipMode() const = 0; // Methods to clip the selected brush or to split it (keeping both parts) virtual void clip() = 0; virtual void splitClip() = 0; // Inverts the clip plane "direction" to determine which part of the brush is kept after clipping virtual void flipClip() = 0; // True when new faces should get caulked virtual bool useCaulkForNewFaces() const = 0; // Returns the name of the caulk shader to be used for clip-created planes virtual const std::string& getCaulkShader() const = 0; // Return or set the view type of the xy view (needed for the projections). virtual OrthoOrientation getViewType() const = 0; virtual void setViewType(OrthoOrientation viewType) = 0; // Returns the pointer to the currently moved clip point virtual ClipPoint* getMovingClip() = 0; virtual void setMovingClip(ClipPoint* clipPoint) = 0; // Retrieves the reference to the coordinates of the currently "selected" clip point virtual Vector3& getMovingClipCoords() = 0; virtual ClipPoint* find(const Vector3& point, OrthoOrientation viewtype, float scale) = 0; // Adds the given point as new clip point. virtual void newClipPoint(const Vector3& point) = 0; // Draws the clip points into the XYView virtual void draw(float scale) = 0; // Updates the clip plane information virtual void update() = 0; // Returns the currently active clip plane (might be invalid) virtual const Plane3& getClipPlane() = 0; }; // The accessor for the clipper module inline IClipper& GlobalClipper() { static module::InstanceReference _reference(MODULE_CLIPPER); return _reference; } ================================================ FILE: include/icolourscheme.h ================================================ #pragma once #include "imodule.h" #include #include "math/Vector3.h" namespace colours { /** * Registry key set when light volumes should be rendered in a single colour * set by the colourscheme, rather than the colour contained in their _color * key. */ constexpr const char* RKEY_OVERRIDE_LIGHTCOL = "user/ui/colour/overrideLightColour"; class IColourItem { public: virtual ~IColourItem() {} // Const and non-const colour accessors virtual const Vector3& getColour() const = 0; virtual Vector3& getColour() = 0; }; /// Interface for a single colour scheme class IColourScheme { public: virtual ~IColourScheme() {} // Iterate over all colours in this scheme virtual void foreachColour(const std::function& functor) = 0; virtual void foreachColour(const std::function& functor) const = 0; // Returns the requested colour object virtual IColourItem& getColour(const std::string& colourName) = 0; // returns the name of this colour scheme virtual const std::string& getName() const = 0; // returns true if the scheme is read-only virtual bool isReadOnly() const = 0; }; /// Module providing access to current and available colour schemes class IColourSchemeManager : public RegisterableModule { public: virtual ~IColourSchemeManager() {} // Visit each known colour scheme with the given functor virtual void foreachScheme(const std::function& functor) = 0; // Get the named scheme virtual IColourScheme& getColourScheme(const std::string& schemeName) = 0; // Checks if the specified scheme already exists virtual bool schemeExists(const std::string& name) = 0; virtual void setActive(const std::string& name) = 0; /// Get a reference to the currently active colour scheme virtual IColourScheme& getActiveScheme() = 0; // greebo: Returns the named colour, returns <0,0,0> if not found virtual Vector3 getColour(const std::string& colourName) = 0; virtual void deleteScheme(const std::string& name) = 0; virtual void copyScheme(const std::string& fromName, const std::string& toName) = 0; // Loads/Saves all the schemes from/to the registry virtual void loadColourSchemes() = 0; virtual void saveColourSchemes() = 0; // Reverts all changes to the current objects and re-load them from the registry virtual void restoreColourSchemes() = 0; // Explicitly store the entity class overrides in the EclassColourManager // This is done by restore/saveColourSchemes automatically and doesn't need to be // called by client code. This is used to let the colour scheme editor force an // update of the eclasses in the current scene to allow for a better preview virtual void emitEclassOverrides() = 0; }; } const char* const MODULE_COLOURSCHEME_MANAGER("ColourSchemeManager"); inline colours::IColourSchemeManager& GlobalColourSchemeManager() { static module::InstanceReference _reference(MODULE_COLOURSCHEME_MANAGER); return _reference; } ================================================ FILE: include/icommandsystem.h ================================================ #pragma once #include #include #include "math/Vector2.h" #include "math/Vector3.h" #include "imodule.h" #include "string/convert.h" namespace cmd { // Use these to define argument types enum ArgumentTypeFlags { ARGTYPE_VOID = 0, ARGTYPE_STRING = 1 << 0, ARGTYPE_INT = 1 << 1, ARGTYPE_DOUBLE = 1 << 2, ARGTYPE_VECTOR3 = 1 << 3, ARGTYPE_VECTOR2 = 1 << 4, // future types go here ARGTYPE_OPTIONAL = 1 << 16, }; /** * @brief A single command argument which may be of several different types. * * The argument maintains a list of type flags which indicate which types this argument may be * interpreted as. For example, an argument constructed from an integer may also be interpreted as * a double, so will have both ARGTYPE_INT and ARGTYPE_DOUBLE. */ class Argument { std::string _strValue; double _doubleValue = 0.0; int _intValue = 0; Vector3 _vector3Value = {0, 0, 0}; Vector2 _vector2Value = {0, 0}; // The type flags std::size_t _type = ARGTYPE_VOID; public: Argument() = default; Argument(const Argument&) = default; // String => Argument constructor Argument(const std::string& str) : _strValue(str), _doubleValue(string::convert(str)), _intValue(string::convert(str)), _vector3Value(string::convert(str)), _vector2Value(Vector2(str)), _type(ARGTYPE_STRING) { tryNumberConversion(); tryVectorConversion(); } // Double => Argument constructor Argument(const double d) : _strValue(string::to_string(d)), _doubleValue(d), _intValue(static_cast(d)), _vector3Value(d,d,d), _vector2Value(d,d), _type(ARGTYPE_DOUBLE) { // Enable INT flag if double value is rounded if (lrint(_doubleValue) == _intValue) { _type |= ARGTYPE_INT; } } // Int => Argument constructor Argument(const int i) : _strValue(string::to_string(i)), _doubleValue(static_cast(i)), _intValue(i), _vector3Value(i,i,i), _vector2Value(i,i), _type(ARGTYPE_INT|ARGTYPE_DOUBLE) // INT can be used as DOUBLE too {} // Vector3 => Argument constructor Argument(const Vector3& v) : _strValue(string::to_string(v[0]) + " " + string::to_string(v[1]) + " " + string::to_string(v[2])), _doubleValue(v.getLength()), _intValue(static_cast(v.getLength())), _vector3Value(v), _vector2Value(v[0], v[1]), _type(ARGTYPE_VECTOR3) {} // Vector2 => Argument constructor Argument(const Vector2& v) : _strValue(string::to_string(v[0]) + " " + string::to_string(v[1]) + " " + string::to_string(v[2])), _doubleValue(v.getLength()), _intValue(static_cast(v.getLength())), _vector3Value(v[0], v[1], 0), _vector2Value(v), _type(ARGTYPE_VECTOR2) {} std::size_t getType() const { return _type; } std::string getString() const { return _strValue; } bool getBoolean() const { return getInt() != 0; } int getInt() const { return _intValue; } double getDouble() const { return _doubleValue; } Vector3 getVector3() const { return _vector3Value; } Vector2 getVector2() const { return _vector2Value; } private: void tryNumberConversion() { // Try to cast the string value to numbers int maybeInt; if (string::tryConvertToInt(_strValue, maybeInt)) { _intValue = maybeInt; _type |= ARGTYPE_INT; } double maybeDouble; if (string::tryConvertToDouble(_strValue, maybeDouble)) { _doubleValue = maybeDouble; _type |= ARGTYPE_DOUBLE; } } void tryVectorConversion() { // Use a stringstream to parse the string std::stringstream strm(_strValue); strm << std::skipws; // Try converting the first two values strm >> _vector2Value.x(); strm >> _vector2Value.y(); if (!strm.fail()) { _type |= ARGTYPE_VECTOR2; // Try to parse the third value strm >> _vector3Value.z(); if (!strm.fail()) { // Third value successfully parsed _type |= ARGTYPE_VECTOR3; // Copy the two values from the parsed Vector2 _vector3Value.x() = _vector2Value.x(); _vector3Value.y() = _vector2Value.y(); } } } }; typedef std::vector ArgumentList; /** * greebo: A command target must take an ArgumentList argument, like this: * * void doSomething(const ArgumentList& args); * * This can be both a free function and a member function. */ typedef std::function Function; /// Convert a zero-argument function into a Function by discarding the ArgumentList template Function noArgs(F f) { return [f](const ArgumentList&) { f(); }; } /** * @brief Signature for a function which can test if a particular command should * be enabled. */ using CheckFunction = std::function; // A command signature consists just of arguments, return type is always void typedef std::vector Signature; /** * greebo: Auto-completion information returned by the CommandSystem * when the user is entering a partial command. */ struct AutoCompletionInfo { // The command prefix this info is referring to std::string prefix; // The candidaes, alphabetically ordered, case-insensitively typedef std::vector Candidates; Candidates candidates; }; /** * @brief Interface for the CommandSystem module. * * Commands are self-contained blocks of code (function calls or lambdas) which * can be invoked from menu items or from typing string commands in the * DarkRadiant console. They can also be called from Python. * * Commands can be invoked programmatically via the executeCommand() method, * which is sometimes useful if the implementing function isn't exposed via a * suitable module interface. Note however that neither the name of the command * (an arbitrary string) or the types of its arguments are checked at * compile-time, so calling C++ methods directly is generally preferable where * possible. */ class ICommandSystem: public RegisterableModule { public: /** * Visit each command/bind using the given lambda. The functor is going to be called * with the command name as argument. */ virtual void foreachCommand(const std::function& functor) = 0; /** * greebo: Declares a new command with the given signature. */ virtual void addCommand(const std::string& name, Function func, const Signature& signature = Signature()) = 0; /** * @brief Add a new command with a check function which can test if the * command is currently runnable. * * This is aimed at commands which are not always available, e.g. because * they require one or more objects to be selected. If the command is not * currently available, the UI might choose to disable the button or menu * item which invokes it. * * @param name * Name of the command. * * @param func * Function to call when the command is invoked. * * @param check * Function to check whether the command should be enabled based on current * application state. */ virtual void addWithCheck(const std::string& name, Function func, CheckFunction check, const Signature& = {}) = 0; /// Returns true if the named command exists virtual bool commandExists(const std::string& name) = 0; /** * @brief Check if the named command is currently runnable. * * This is just a signal to the UI that a command should be disabled; the * command system does NOT guarantee that a command for which canExecute() * returns false won't actually be invoked by a subsequent call to * executeCommand(). */ virtual bool canExecute(const std::string& name) const = 0; /** * Remove a named command. */ virtual void removeCommand(const std::string& name) = 0; /** * greebo: Define a new statement, which consists of a name and a * string to execute. * * Consider this as some sort of macro. * * @statementName: The name of the statement, e.g. "exportASE" * @string: The string to execute. * @saveStatementToRegistry: when TRUE (default) this statement/bind * is saved to the registry at program shutdown. Pass FALSE if you * don't want to let this statement persist between sessions. */ virtual void addStatement(const std::string& statementName, const std::string& string, bool saveStatementToRegistry = true) = 0; /** * Visit each statement (bind) using the given lambda. The functor is going to be called * with the statement name as argument. */ virtual void foreachStatement(const std::function& functor, bool customStatementsOnly = false) = 0; /** * Returns the signature for the named command or bind. Statements * always have an empty signature. */ virtual Signature getSignature(const std::string& name) = 0; /** * greebo: Executes the given string as if the user had typed it * in the command console. The passed string can be a sequence of * statements separated by semicolon ';' characters. Each statement * can have zero or more arguments, separated by spaces. * * It is possible to pass string arguments by using * double- or single-quote characters. * e.g. "This; string; will be; treated as a whole". * * The last command needs not to be delimited by a semicolon. * * Example: nudgeLeft; nudgeRight -1 0 0; write "Bla! Test" */ virtual void execute(const std::string& input) = 0; /// Execute the named command with the given list of arguments virtual void executeCommand(const std::string& name, const ArgumentList& args = {}) = 0; /// Convenience method to execute a command with 1 argument void executeCommand(const std::string& name, const Argument& arg1) { executeCommand(name, ArgumentList{arg1}); } /// Convenience method to execute a command with 2 arguments void executeCommand(const std::string& name, const Argument& arg1, const Argument& arg2) { executeCommand(name, {arg1, arg2}); } /** * greebo: Returns autocompletion info for the given prefix. */ virtual AutoCompletionInfo getAutoCompletionInfo(const std::string& prefix) = 0; }; typedef std::shared_ptr ICommandSystemPtr; } // namespace cmd const char* const MODULE_COMMANDSYSTEM("CommandSystem"); // This is the accessor for the commandsystem inline cmd::ICommandSystem& GlobalCommandSystem() { static module::InstanceReference _reference(MODULE_COMMANDSYSTEM); return _reference; } ================================================ FILE: include/icomparablenode.h ================================================ #pragma once #include namespace scene { /** * Prototype of a comparable scene node, providing hash information * for comparison to another node. Nodes of the same type can be compared against each other. */ class IComparableNode { public: virtual ~IComparableNode() {} // Returns the fingerprint (checksum) of this node, to allow for quick // matching against other nodes of the same type. Fingerprints of different // types are not comparable, be sure to check the node type first. virtual std::string getFingerprint() = 0; }; // The number of digits that are considered when hashing floating point values in fingerprinting constexpr std::size_t SignificantFingerprintDoubleDigits = 6; } ================================================ FILE: include/icounter.h ================================================ #pragma once #include #include "imodule.h" class ICounter { public: /** Destructor */ virtual ~ICounter() {} /** greebo: Decrements/increments the counter. */ virtual void increment() = 0; virtual void decrement() = 0; /** greebo: Returns the current count. */ virtual std::size_t get() const = 0; }; // Known counters enum CounterType { counterBrushes, counterPatches, counterEntities, }; const char* const MODULE_COUNTER("Counters"); /** greebo: This abstract class defines the interface to the core application. * Use this to access methods from the main codebase in radiant/ */ class ICounterManager : public RegisterableModule { public: // Returns the Counter object of the given type virtual ICounter& getCounter(CounterType counter) = 0; virtual sigc::signal& signal_countersChanged() = 0; }; inline ICounterManager& GlobalCounters() { static module::InstanceReference _reference(MODULE_COUNTER); return _reference; } ================================================ FILE: include/icurve.h ================================================ #ifndef ICURVE_H_ #define ICURVE_H_ #include "inode.h" class CurveNode { public: /** destructor */ virtual ~CurveNode() {} /** greebo: Returns true if the curve has 0 control points. */ virtual bool hasEmptyCurve() = 0; /** greebo: Appends a control point at the end of the chain. */ virtual void appendControlPoints(unsigned int numPoints) = 0; /** greebo: As the name states, this removes the selected * control points from the curve. */ virtual void removeSelectedControlPoints() = 0; /** greebo: This inserts a control point BEFORE each * selected control point of the curve. * Naturally, this doesn't work if the first vertex * is selected. */ virtual void insertControlPointsAtSelected() = 0; /** greebo: Converts the type of the curve from CatmullRom * to NURBS and vice versa. */ virtual void convertCurveType() = 0; }; typedef std::shared_ptr CurveNodePtr; inline CurveNodePtr Node_getCurve(const scene::INodePtr& node) { return std::dynamic_pointer_cast(node); } #endif /*ICURVE_H_*/ ================================================ FILE: include/idatastream.h ================================================ /* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General 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(INCLUDED_IDATASTREAM_H) #define INCLUDED_IDATASTREAM_H #include class StreamBase { public: virtual ~StreamBase() {} typedef std::size_t size_type; typedef unsigned char byte_type; }; /// \brief A read-only byte-stream. class InputStream : public StreamBase { public: /// \brief Attempts to read the next \p length bytes from the stream to \p buffer. /// Returns the number of bytes actually stored in \p buffer. virtual size_type read(byte_type* buffer, size_type length) = 0; }; /// \brief A write-only byte-stream. class OutputStream : public StreamBase { public: /// \brief Attempts to write \p length bytes to the stream from \p buffer. /// Returns the number of bytes actually read from \p buffer. virtual size_type write(const byte_type* buffer, size_type length) = 0; }; class SeekableStream { public: typedef int offset_type; typedef std::size_t position_type; enum seekdir { beg, cur, end, }; virtual ~SeekableStream() {} /// \brief Sets the current \p position of the stream relative to the start. virtual position_type seek(position_type position) = 0; /// \brief Sets the current \p position of the stream relative to either the start, end or current position. virtual position_type seek(offset_type offset, seekdir direction) = 0; /// \brief Returns the current position of the stream. virtual position_type tell() const = 0; }; /// \brief A seekable read-only byte-stream. class SeekableInputStream : public InputStream, public SeekableStream { }; /// \brief A seekable write-only byte-stream. class SeekableOutputStream : public OutputStream, public SeekableStream { }; #endif ================================================ FILE: include/ideclmanager.h ================================================ #pragma once #include #include "imodule.h" #include "ifilesystem.h" #include "igameresource.h" #include "idecltypes.h" namespace decl { /// Represents a declaration block as found in the various decl files. /// /// Holds the name of the block, its typename and the raw block contents including /// whitespace and comments but exluding the outermost brace pair struct DeclarationBlockSource : game::IResource { // The type name of this block (e.g. "table") std::string typeName; // The name of this block (e.g. "sinTable" or "textures/common/caulk" std::string name; // The block contents (excluding braces) std::string contents; // The mod this syntax has been defined in std::string modName; // The VFS info of the file this syntax is located vfs::FileInfo fileInfo; std::string getModName() const override { return modName; } }; // Common interface shared by all the declarations supported by a certain game type class IDeclaration : public game::IResource { public: virtual ~IDeclaration() {} using Ptr = std::shared_ptr; // The full name of this declaration, e.g. "textures/common/caulk" virtual const std::string& getDeclName() const = 0; // Change the name of this decl. Don't use this directly in client code, use // GlobalDeclarationManager().renameDeclaration() instead. virtual void setDeclName(const std::string& newName) = 0; // The original full name of this declaration, e.g. "textures/common/caulk", // as parsed from the decl file. This is used internally for saving/deleting // declarations, client code usually wants to use getDeclName(). virtual const std::string& getOriginalDeclName() const = 0; // Update the name of this decl as it appears in the decl file // Used internally after saving a renamed decl. virtual void setOriginalDeclName(const std::string& newName) = 0; // The type of this declaration virtual Type getDeclType() const = 0; /// Get the visibility of this declaration, which determines whether it should be /// shown in the relevant UI browser. /// /// The visibility of a particular declaration may be determined by a separate /// assets.lst file, or in any declaration-specific manner. /// /// Logically this method should be const, but currently it isn't because it might /// trigger on-demand parsing in certain subclasses. virtual vfs::Visibility getVisibility() { return vfs::Visibility::NORMAL; } // The raw syntax block (without the outer curly braces) used to construct this decl virtual const DeclarationBlockSource& getDeclSource() = 0; // Set the block contents of this declaration. // Implementations are free to either (re-)parse immediately or deferred. virtual void setDeclSource(const DeclarationBlockSource& block) = 0; // Returns the mod-relative path to the file this decl has been declared in virtual std::string getDeclFilePath() const = 0; // Sets the file info as contained in the block syntax virtual void setFileInfo(const vfs::FileInfo& fileInfo) = 0; // Returns the value of the internally used parse epoch counter virtual std::size_t getParseStamp() const = 0; // Sets the internally used parse epoch counter virtual void setParseStamp(std::size_t parseStamp) = 0; // Fired when this declaration changed (i.e. as result of a reloadDecls // operation or a change in an editor). virtual sigc::signal& signal_DeclarationChanged() = 0; }; // Factory interface being able to create a single declaration type class IDeclarationCreator { public: virtual ~IDeclarationCreator() {} using Ptr = std::shared_ptr; // Returns the declaration type this creator can handle virtual Type getDeclType() const = 0; // Creates an empty declaration with the given name virtual IDeclaration::Ptr createDeclaration(const std::string& name) = 0; }; // Central service class holding all the declarations in the active game, // like entityDefs, materials, skins, etc. // Searches registered VFS folders and parses the contents of the matching files // making use of the associated IDeclarationParser instances. class IDeclarationManager : public RegisterableModule { public: virtual ~IDeclarationManager() override {} // Registers the declaration typename (e.g. "material") and associates it with the given creator // It's not allowed to register more than one creator for a single typename // Note: The given typename will be treated case-insensitively by the decl parser. virtual void registerDeclType(const std::string& typeName, const IDeclarationCreator::Ptr& creator) = 0; // Unregisters the given typename and the associated creator virtual void unregisterDeclType(const std::string& typeName) = 0; // Associates the given VFS folder (with trailing slash) to a certain declaration type // all files matching the given file extension (without dot) will be searched and parsed. // The folder will not be recursively searched for files, only immediate children will be processed. // Any untyped declaration blocks found in the files will be assumed to be of the given defaultType. // All explicitly typed resources will be processed using the parser that has been previously // associated in registerDeclType() // Registering a folder will immediately trigger parsing of all contained files matching the criteria. virtual void registerDeclFolder(Type defaultType, const std::string& vfsFolder, const std::string& extension) = 0; // Find the declaration with the given type and name // Returns an empty reference if no declaration with that name could be found virtual IDeclaration::Ptr findDeclaration(Type type, const std::string& name) = 0; // Find the declaration with the given type and name, or creates a default declaration // of the given type if nothing was found. Will always return a non-empty reference. // Throws std::invalid_argument exception of the type has not even been registered virtual IDeclaration::Ptr findOrCreateDeclaration(Type type, const std::string& name) = 0; // Iterate over all known declarations, using the given visitor virtual void foreachDeclaration(Type type, const std::function& functor) = 0; // Renames the declaration from oldName to newName. The new name must not be in use by any other declaration, // and it must be different from oldName, otherwise renaming will fail. // Returns true if the old declaration existed and could successfully be renamed, false on any failure. virtual bool renameDeclaration(Type type, const std::string& oldName, const std::string& newName) = 0; // Removes the given declaration both from memory and the decl file, if there is one. // Only declarations stored in physical files (or unsaved ones) can be removed. // Attempting to remove a read-only declaration (e.g. decls saved in PK4 archives) // will cause a std::logic_error to be thrown. virtual void removeDeclaration(Type type, const std::string& name) = 0; // Re-load all declarations. // All declaration references will stay intact, only their contents will be refreshed virtual void reloadDeclarations() = 0; // Saves the given declaration to a physical declaration file. Depending on the original location // of the declaration the outcome will be different. // // It is required for the declaration to have valid file information set on its syntax block, // otherwise the declaration manager will not know where to save it to and throws std::invalid_argument. // // Case #1: Newly created declarations (created through findOrCreateDeclaration): // The decl will be appended to the given file. The file will be created if required. // Case #2: Existing declarations (with their original file being a physical file): // The decl in the file will be replaced with its new syntax block. All the content before and // after the declaration will be left untouched. // Case #3: Existing declarations (with their original file being stored within a PK4): // The decl file will be copied and saved to its corresponding physical location, effectively // creating a file that will override the one in the PK4. The decl will be merged into the file // just like in case #2 virtual void saveDeclaration(const IDeclaration::Ptr& decl) = 0; // Signal emitted right before decls are being reloaded virtual sigc::signal& signal_DeclsReloading(Type type) = 0; // Signal emitted when the decls of the given type have been (re-)loaded // Note that this signal can be fired on an arbitrary thread virtual sigc::signal& signal_DeclsReloaded(Type type) = 0; // Signal emitted when a declaration is renamed // The type, the old name and the new name will be passed as arguments virtual sigc::signal& signal_DeclRenamed() = 0; // Signal emitted when a declaration has been created (e.g. by findOrCreateDeclaration), // passing the type and name of the created decl as argument virtual sigc::signal& signal_DeclCreated() = 0; // Signal emitted when a declaration has been removed (by removeDeclaration), // passing the type and name of the removed decl as argument virtual sigc::signal& signal_DeclRemoved() = 0; }; } constexpr const char* const MODULE_DECLMANAGER("DeclarationManager"); inline decl::IDeclarationManager& GlobalDeclarationManager() { static module::InstanceReference _reference(MODULE_DECLMANAGER); return _reference; } ================================================ FILE: include/idecltypes.h ================================================ #pragma once #include #include // Some X11 headers are defining this #ifdef None #undef None #endif namespace decl { // Enumeration of declaration types supported by DarkRadiant enum class Type { Undetermined = -2, None = -1, Material = 0, Table, EntityDef, SoundShader, ModelDef, Particle, Skin, Fx, // These are used in unit tests only TestDecl, TestDecl2, }; inline std::string getTypeName(Type type) { switch (type) { case Type::Undetermined: return "Undetermined"; case Type::None: return "None"; case Type::Material: return "Material"; case Type::Table: return "Table"; case Type::EntityDef: return "EntityDef"; case Type::SoundShader: return "SoundShader"; case Type::ModelDef: return "ModelDef"; case Type::Particle: return "Particle"; case Type::Skin: return "Skin"; case Type::Fx: return "Fx"; case Type::TestDecl: return "TestDecl"; case Type::TestDecl2: return "TestDecl2"; default: throw std::runtime_error("Unhandled decl type"); } } } ================================================ FILE: include/ieclass.h ================================================ /** * \defgroup eclass Entity class manager * \file ieclass.h * \brief Entity Class definition loader API. * \ingroup eclass */ #pragma once #include "ideclmanager.h" #include "imodule.h" #include #include #include #include "scene/EntityClass.h" /* FORWARD DECLS */ class Shader; typedef std::shared_ptr ShaderPtr; class AABB; /** * Structure ontains the information of a model {} block as defined in a * Doom3 .def file. * * \ingroup eclass */ class IModelDef : public decl::IDeclaration { public: using Ptr = std::shared_ptr; // The def this model is inheriting from (empty if there's no parent) virtual const Ptr& getParent() = 0; // The MD5 mesh used by this modelDef virtual const std::string& getMesh() = 0; // The named skin virtual const std::string& getSkin() = 0; // The md5anim file name for the given anim key (e.g. "idle" or "af_pose") virtual std::string getAnim(const std::string& animKey) = 0; // Returns a dictionary of all the animations declared on this model def using Anims = std::map; virtual const Anims& getAnims() = 0; }; /** * EntityClass visitor interface. * * \ingroup eclass */ class EntityClassVisitor { public: virtual ~EntityClassVisitor() {} virtual void visit(const scene::EntityClass::Ptr& eclass) = 0; }; constexpr const char* const MODULE_ECLASSMANAGER("EntityClassManager"); /** * EntityClassManager interface. The entity class manager is responsible for * maintaining a list of available entity classes which the EntityCreator can * insert into a map. * * \ingroup eclass */ class IEntityClassManager : public RegisterableModule { public: /** * Return the scene::EntityClass corresponding to the given name, creating it if * necessary. If it is created, the has_brushes parameter will be used to * determine whether the new entity class should be brush-based or not. * * @deprecated * Use findClass() instead. */ virtual scene::EntityClass::Ptr findOrInsert(const std::string& name, bool has_brushes) = 0; /** * Lookup an entity class by name. If the class is not found, a null pointer * is returned. * * @param name * Name of the entity class to look up. */ virtual scene::EntityClass::Ptr findClass(const std::string& name) = 0; /** * Iterate over all entity defs using the given visitor. */ virtual void forEachEntityClass(EntityClassVisitor& visitor) = 0; // Iterate over all entityDefs using the given function object virtual void forEachEntityClass(const std::function& functor) = 0; /** * greebo: This reloads the entityDefs and modelDefs from all files. Does not * change the scenegraph, only the contents of the EClass objects are * re-parsed. All scene::EntityClass::Ptrs remain valid, no entityDefs are removed. * * Note: This is NOT the same as unrealise + realise */ virtual void reloadDefs() = 0; /** * greebo: Finds the model def with the given name. Might return NULL if not found. */ virtual IModelDef::Ptr findModel(const std::string& name) = 0; /** * Iterate over each ModelDef using the given function object. */ virtual void forEachModelDef(const std::function& functor) = 0; }; /** * Return the global EntityClassManager to the application. * * \ingroup eclass */ inline IEntityClassManager& GlobalEntityClassManager() { static module::InstanceReference _reference(MODULE_ECLASSMANAGER); return _reference; } ================================================ FILE: include/ieclasscolours.h ================================================ #pragma once #include #include #include "imodule.h" #include "scene/EntityClass.h" #include "math/Vector3.h" namespace eclass { /** * Manages the entity class colour overrides that are applied * to certain eclasses as defined in the currently active * colour scheme. */ class IColourManager : public RegisterableModule { public: virtual ~IColourManager() {} // Register an override for the given entity class, such that the wire/fill shader // colours of the named entity class are using the given colour instead of the one // defined in the entityDef block. // Adding an override for an entity class will replace any existing overrides. // The colour is given in RGB values with each component in the interval [0..1]. virtual void addOverrideColour(const std::string& eclass, const Vector4& colour) = 0; /** * \brief Applies a possible colour override to the given entity class. * * If an override was found, the entity class's colour will be changed with * setColour(). * * \return true if an override was found, false otherwise. */ virtual bool applyColours(scene::EntityClass& eclass) = 0; // Visit each override definition with the given functor virtual void foreachOverrideColour(const std::function& functor) = 0; // Removes the override colour for the given entity class virtual void removeOverrideColour(const std::string& eclass) = 0; // Removes all registered overrides virtual void clearOverrideColours() = 0; // Signal invoked when an override of a specific eclass is added, changed or removed // function signature: void(const std::string& eclass, bool hasBeenRemoved) virtual sigc::signal& sig_overrideColourChanged() = 0; }; } const char* const MODULE_ECLASS_COLOUR_MANAGER("EclassColourManager"); /** * Return the global IEClassColourManager to the application. * \ingroup eclass */ inline eclass::IColourManager& GlobalEclassColourManager() { static module::InstanceReference _reference(MODULE_ECLASS_COLOUR_MANAGER); return _reference; } ================================================ FILE: include/ieditstopwatch.h ================================================ #pragma once #include "imodule.h" #include namespace map { /** * Stopwatch to measure the time spent editing a particular map. * The time is persisted to the .darkradiant/.mapx file and keeps running * as long as the application is in focus. * * The class will maintain its own internal timer class, but will broadcast * a query message (type is IMessage::ApplicationIsActiveQuery) over the * MessageBus such that the UI module can react and prevent the timer * from increasing when the application is not in focus or blocked * in some other way. */ class IMapEditStopwatch : public RegisterableModule { public: virtual ~IMapEditStopwatch() {} // Starts the stopwatch, the map edit timer will start ticking (again) // This does not reset the timings virtual void start() = 0; // Stops the stopwatch, the map edit timer will not be increased anymore // This does not reset the timings virtual void stop() = 0; // Gets the total number of seconds the map has been edited virtual unsigned long getTotalSecondsEdited() = 0; // Sets the total number of seconds the map has been edited so far // This is used when loading maps from disk, to restore the timer to its previous state virtual void setTotalSecondsEdited(unsigned long newValue) = 0; // Signal emitted when the timer value changes virtual sigc::signal& sig_TimerChanged() = 0; }; } const char* const MODULE_EDITING_STOPWATCH("EditingStopwatch"); inline map::IMapEditStopwatch& GlobalMapEditStopwatch() { static module::InstanceReference _reference(MODULE_EDITING_STOPWATCH); return _reference; } ================================================ FILE: include/ientity.h ================================================ #pragma once #include "inode.h" #include "imodule.h" #include "irender.h" #include #include "scene/scene_fwd.h" #include "scene/EntityClass.h" // Observes a single entity key value and gets notified on change class KeyObserver: public sigc::trackable { public: using Ptr = std::shared_ptr; virtual ~KeyObserver() {} /** * This event gets called when the observed keyvalue changes. * The new value is passed as argument, which can be an empty string. */ virtual void onKeyValueChanged(const std::string& newValue) = 0; }; /// Callback for an entity key value change using KeyObserverFunc = sigc::slot; inline bool Node_isEntity(const scene::INodePtr& node) { //assert(!((std::dynamic_pointer_cast(node) != nullptr) ^ (node->getNodeType() == scene::INode::Type::Entity))); return node->getNodeType() == scene::INode::Type::Entity; } // Represents a set of selected entities class IEntitySelection { public: virtual ~IEntitySelection() {} // True if there's no selected entity available virtual bool empty() const = 0; // Returns the number of selected entities virtual std::size_t size() const = 0; // Iterates over each selected entity node, invoking the given functor virtual void foreachEntity(const std::function& functor) = 0; // Returns the key value shared by all entities in this set, or an empty string // if there is no such value. virtual std::string getSharedKeyValue(const std::string& key, bool includeInherited) = 0; }; /** * greebo: This is an abstract representation of a target. * In Doom3 maps, a Target can be any entity node, that's * why this object encapsulates a reference to an actual * scene::INode. * * Note: Such a Target object can be empty. That's the case for * entities referring to non-existing entities in their * "target" spawnarg. * * All ITargetableObjects are owned by the TargetManager class. */ class ITargetableObject { public: virtual ~ITargetableObject() {} // Returns the scene node behind this target. If the named target // cannot be resolved in the current scene, an empty pointer is returned. virtual const scene::INode* getNode() const = 0; // Use this method to check whether the node can be resolved virtual bool isEmpty() const = 0; }; typedef std::shared_ptr ITargetableObjectPtr; /** * greebo: The TargetManager keeps track of all ITargetableObjects * in the current scene/map. A TargetManager instance is owned * by the RootNode. TargetManager instances can be acquired through * the EntityCreator interface. * * Clients acquire a named ITargetableObjectPtr by calling getTarget(). This * always succeeds - if the named ITargetableObject is not found, * a new, empty one is created. * * ITargetableObject object (can be empty) * ________ * / \ * Entity | | * TargetKey ----->>| -------->> holds scene::INodePtr (==NULL, if empty) * | | * \________/ */ class ITargetManager { public: /** * Returns the Target with the given name. * This never returns NULL, an ITargetableObject is created if it doesn't exist yet. */ virtual ITargetableObjectPtr getTarget(const std::string& name) = 0; /** * greebo: Associates the named Target with the given scene::INode. * The Target will be created if it doesn't exist yet. */ virtual void associateTarget(const std::string& name, const scene::INode& node) = 0; // Will be called by a TargetableNode to notify about visibility changes virtual void onTargetVisibilityChanged(const std::string& name, const scene::INode& node) = 0; // Will be called by a TargetableNode to notify about a position change virtual void onTargetPositionChanged(const std::string& name, const scene::INode& node) = 0; /** * greebo: Disassociates the Target from the given name. The node * must also be passed to allow the manager to check the request. * Otherwise it would be possible for cloned nodes to dissociate * the target from their source node. */ virtual void clearTarget(const std::string& name, const scene::INode& node) = 0; }; typedef std::shared_ptr ITargetManagerPtr; enum class LightEditVertexType : std::size_t { StartEndDeselected, StartEndSelected, Inactive, Deselected, Selected, NumberOfVertexTypes, }; constexpr const char* const RKEY_SHOW_ENTITY_NAMES("user/ui/xyview/showEntityNames"); constexpr const char* const RKEY_SHOW_ALL_SPEAKER_RADII = "user/ui/showAllSpeakerRadii"; constexpr const char* const RKEY_SHOW_ALL_LIGHT_RADII = "user/ui/showAllLightRadii"; constexpr const char* const RKEY_DRAG_RESIZE_SYMMETRICALLY = "user/ui/dragResizeEntitiesSymmetrically"; constexpr const char* const RKEY_ALWAYS_SHOW_LIGHT_VERTICES = "user/ui/alwaysShowLightVertices"; constexpr const char* const RKEY_FREE_OBJECT_ROTATION = "user/ui/rotateObjectsIndependently"; constexpr const char* const RKEY_SHOW_ENTITY_ANGLES = "user/ui/xyview/showEntityAngles"; /** * Global entity settings affecting appearance, render options, etc. */ class IEntitySettings { public: virtual ~IEntitySettings() {} virtual const Vector3& getLightVertexColour(LightEditVertexType type) const = 0; virtual void setLightVertexColour(LightEditVertexType type, const Vector3& value) = 0; virtual bool getRenderEntityNames() const = 0; virtual void setRenderEntityNames(bool value) = 0; virtual bool getShowAllSpeakerRadii() const = 0; virtual void setShowAllSpeakerRadii(bool value) = 0; virtual bool getShowAllLightRadii() const = 0; virtual void setShowAllLightRadii(bool value) = 0; virtual bool getDragResizeEntitiesSymmetrically() const = 0; virtual void setDragResizeEntitiesSymmetrically(bool value) = 0; virtual bool getAlwaysShowLightVertices() const = 0; virtual void setAlwaysShowLightVertices(bool value) = 0; virtual bool getFreeObjectRotation() const = 0; virtual void setFreeObjectRotation(bool value) = 0; virtual bool getShowEntityAngles() const = 0; virtual void setShowEntityAngles(bool value) = 0; virtual sigc::signal& signal_settingsChanged() = 0; }; constexpr const char* const MODULE_ENTITY("EntityModule"); /** * \brief * Interface for the entity module. */ class IEntityModule : public RegisterableModule { public: virtual ~IEntityModule() {} /// Create an entity node with the given entity class. virtual EntityNodePtr createEntity(const scene::EntityClass::Ptr& eclass) = 0; // Constructs a new targetmanager instance (used by root nodes) virtual ITargetManagerPtr createTargetManager() = 0; // Access to the settings manager virtual IEntitySettings& getSettings() = 0; /** * Create an instance of the given entity at the given position, and return * the Node containing the new entity. * * @returns: the scene::EntityNodePtr referring to the new entity. * @throws: cmd::ExecutionFailure if anything goes wrong or the selection is not suitable. */ virtual EntityNodePtr createEntityFromSelection(const std::string& name, const Vector3& origin) = 0; }; inline IEntityModule& GlobalEntityModule() { static module::InstanceReference _reference(MODULE_ENTITY); return _reference; } ================================================ FILE: include/ifavourites.h ================================================ #pragma once #include #include #include "imodule.h" namespace game { /** * Favourite Management interface keeping track of resources * that have been tagged as favourite by the user. * * Each favourite obejct has a typename and a (unique) identifier. * The typename is treated case-insensitively - it is used as tag identifier * when persisting the set, therefore it must consist of word characters only. */ class IFavouritesManager : public RegisterableModule { public: virtual ~IFavouritesManager() {} /** * Adds the given favourite object to the set of favourites * * @typeName: Type name of the favourite, like "prefab" or "material" * Favourites with the same type name are grouped. * * @identifier: The identifier of this favourite object, * like a file path or a declaration name */ virtual void addFavourite(const std::string& typeName, const std::string& identifier) = 0; // Removes the favourite with the given type and identifier from the set of favourites virtual void removeFavourite(const std::string& typeName, const std::string& identifier) = 0; // Returns true if the given type/name combination is listed as favourite virtual bool isFavourite(const std::string& typeName, const std::string& identifier) = 0; // Returns the whole set of favourites for the given type name virtual std::set getFavourites(const std::string& typeName) = 0; // Returns the changed signal for the given type - will be fired when the set changes // Requesting a signal for an empty typename will trigger a std::invalid_argument exception virtual sigc::signal& getSignalForType(const std::string& typeName) = 0; }; } constexpr const char* const MODULE_FAVOURITES_MANAGER("FavouritesManager"); inline game::IFavouritesManager& GlobalFavouritesManager() { static module::InstanceReference _reference(MODULE_FAVOURITES_MANAGER); return _reference; } ================================================ FILE: include/ifilesystem.h ================================================ #pragma once /** * \defgroup vfs Virtual filesystem * \file ifilesystem.h * Interface types for the VFS module. */ #include #include #include #include #include #include #include #include "imodule.h" #include "iarchive.h" namespace vfs { // Extension of std::list to check for existing paths before inserting new ones class SearchPaths : public std::list { public: bool insertIfNotExists(const std::string& path) { if (std::find(begin(), end(), path) != end()) { return false; } push_back(path); return true; } }; /// Visibility of an asset in the mod installation enum class Visibility { /// Standard visibility, shown in all relevant areas NORMAL, /// Hidden from selectors, but rendered as normal in the map itself HIDDEN }; inline std::ostream& operator<< (std::ostream& s, const Visibility& v) { if (v == Visibility::HIDDEN) return s << "Visibility::HIDDEN"; else if (v == Visibility::NORMAL) return s << "Visibility::NORMAL"; else return s << "Visibility(invalid)"; } /// Metadata about a file in the virtual filesystem class FileInfo { private: // Info provider to load additional info on demand, used by e.g. getSize() IArchiveFileInfoProvider* _infoProvider; public: FileInfo() : FileInfo(std::string(), std::string(), Visibility::HIDDEN) {} FileInfo(const std::string& topDir_, const std::string& name_, Visibility visibility_) : _infoProvider(nullptr), topDir(topDir_), name(name_), visibility(visibility_) {} FileInfo(const std::string& topDir_, const std::string& name_, Visibility visibility_, IArchiveFileInfoProvider& infoProvider) : FileInfo(topDir_, name_, visibility_) { _infoProvider = &infoProvider; } FileInfo(const FileInfo& other) = default; FileInfo(FileInfo&& other) = default; FileInfo& operator=(const FileInfo& other) = default; FileInfo& operator=(FileInfo&& other) = default; /// Top-level directory (if any), e.g. "def" or "models" std::string topDir; /// Name of the file, including intermediate directories under the topDir std::string name; /// Visibility of the file Visibility visibility = Visibility::NORMAL; bool isEmpty() const { return name.empty(); } /// Return the full mod-relative path, including the containing directory std::string fullPath() const { if (topDir.empty()) return name; else return topDir + (topDir.back() == '/' ? "" : "/") + name; } // See IArchiveFileInfoProvider::getFileSize std::size_t getSize() const { return _infoProvider ? _infoProvider->getFileSize(fullPath()) : 0; } // See IArchiveFileInfoProvider::getIsPhysicalFile bool getIsPhysicalFile() const { return _infoProvider ? _infoProvider->getIsPhysical(fullPath()) : false; } // See IArchiveFileInfoProvider::getArchivePath std::string getArchivePath() const { return _infoProvider ? _infoProvider->getArchivePath(fullPath()) : ""; } /// Equality comparison with another FileInfo bool operator== (const FileInfo& rhs) const { return topDir == rhs.topDir && name == rhs.name && visibility == rhs.visibility; } }; /** * Main interface for the virtual filesystem. * * The virtual filesystem provides a unified view of the contents of Doom 3's * base and mod subdirectories, including the contents of PK4 files. Assets can * be retrieved using a single unique path, without needing to know whereabouts * in the physical filesystem the asset is located. * * \ingroup vfs */ class VirtualFileSystem : public RegisterableModule { public: virtual ~VirtualFileSystem() {} // Functor taking the filename and visibility as argument. The filename is // relative to the base path passed to the GlobalFileSystem().foreach*() // method. typedef std::function VisitorFunc; // Initialises the filesystem using the given search order. virtual void initialise(const SearchPaths& vfsSearchPaths, const std::set& allowedArchiveExtensions) = 0; // Returns true if the filesystem has already been initialised virtual bool isInitialised() const = 0; /// \brief Shuts down the filesystem. virtual void shutdown() = 0; // Returns the extension set this VFS instance has been initialised with virtual const std::set& getArchiveExtensions() const = 0; // A signal that is emitted when the VFS has been initialised, i.e. the paths have been // set, the archives/directories are known and can be traversed virtual sigc::signal& signal_Initialised() = 0; // Returns the number of files in the VFS matching the given filename virtual int getFileCount(const std::string& filename) = 0; /// \brief Returns the file identified by \p filename opened in binary mode, or 0 if not found. // greebo: Note: expects the filename to be normalised (forward slashes, trailing slash). virtual ArchiveFilePtr openFile(const std::string& filename) = 0; /// \brief Returns the file identified by \p filename opened in binary mode, or 0 if not found. // This is a variant of openFile taking an absolute path as argument. virtual ArchiveFilePtr openFileInAbsolutePath(const std::string& filename) = 0; /// \brief Returns the file identified by \p filename opened in text mode, or 0 if not found. virtual ArchiveTextFilePtr openTextFile(const std::string& filename) = 0; /// \brief Returns the file identified by \p filename opened in text mode, or NULL if not found. /// This is a variant of openTextFile taking an absolute path as argument. virtual ArchiveTextFilePtr openTextFileInAbsolutePath(const std::string& filename) = 0; // Opens an independent archive located in the given physical path. // (This archive can be located somewhere outside the current VFS hierarchy.) // Loading this archive won't have any effect on the VFS setup, it is opened stand-alone. virtual IArchive::Ptr openArchiveInAbsolutePath(const std::string& pathToArchive) = 0; /// \brief Calls the visitor function for each file under \p basedir matching \p extension. /// Use "*" as \p extension to match all file extensions. virtual void forEachFile(const std::string& basedir, const std::string& extension, const VisitorFunc& visitorFunc, std::size_t depth = 1) = 0; // Similar to forEachFile, this routine traverses an absolute path // searching for files matching a certain extension and invoking // the given visitor functor on each occurrence. virtual void forEachFileInAbsolutePath(const std::string& path, const std::string& extension, const VisitorFunc& visitorFunc, std::size_t depth = 1) = 0; // Similar to forEachFile, this routine traverses an archive in the given path // searching for files matching a certain extension and invoking // the given visitor functor on each occurrence. virtual void forEachFileInArchive(const std::string& absoluteArchivePath, const std::string& extension, const VisitorFunc& visitorFunc, std::size_t depth = 1) = 0; /// \brief Returns the absolute filename for a relative \p name, or "" if not found. virtual std::string findFile(const std::string& name) = 0; /// \brief Returns the filesystem root for an absolute \p name, or "" if not found. /// This can be used to convert an absolute name to a relative name. virtual std::string findRoot(const std::string& name) = 0; // Returns the list of registered VFS paths, ordered by search priority virtual const SearchPaths& getVfsSearchPaths() = 0; // Gets the file info structure for the given VFS file. // The info structure will be empty if the file was not located in the current VFS tree virtual vfs::FileInfo getFileInfo(const std::string& vfsRelativePath) = 0; }; } constexpr const char* const MODULE_VIRTUALFILESYSTEM("VirtualFileSystem"); inline vfs::VirtualFileSystem& GlobalFileSystem() { static module::InstanceReference _reference(MODULE_VIRTUALFILESYSTEM); return _reference; } ================================================ FILE: include/ifiletypes.h ================================================ #pragma once #include #include #include "imodule.h" /** * Simple structure to store a file pattern (e.g. "*.map") * along with its name (e.g. "Map files") and extension. */ struct FileTypePattern { // The user-friendly name ("Doom 3 Map") std::string name; // The extension in lowercase ("map") std::string extension; // The mask pattern ("*.map") std::string pattern; // Optional icon string, referring to an image in the bitmaps folder std::string icon; // Constructor with optional initialisation parameters FileTypePattern(const std::string& name_ = "", const std::string& extension_ = "", const std::string& pattern_ = "", const std::string& icon_ = "") : name(name_), extension(extension_), pattern(pattern_), icon(icon_) {} }; typedef std::list FileTypePatterns; const char* const MODULE_FILETYPES = "FileTypes"; /** * Interface for the FileType registry module. This module retains a list of * FileTypePattern objects along with their associated module names. */ class IFileTypeRegistry : public RegisterableModule { public: /** * greebo: Registers an extension (e.g. "map") for a certain file type ("prefab"). * Common file types are "map", "prefab" and "model", each of them can have one * or more extensions associated in a certain order ("prefab" => "pfb", "map", "reg", * or "map" => "map", "reg", "pfb"). The order is important e.g. for the file * filters in the Map Open dialog. * * The pattern argument is a structure containing the lowercase extensions as well * as the display name and the filter pattern used in the file chooser dialogs. * * If an extension is already associated with the given filetype, it is ignored. * New extensions are added to the end of the list. * * @param fileType: the file type which an extension should be associated to. * @param pattern: the extension as well as the display name and a pattern ("*.map") */ virtual void registerPattern(const std::string& fileType, const FileTypePattern& pattern) = 0; /** * Retrieve a list of patterns for the given file type (e.g. "prefab" or "map"). * * @returns: a list of FileTypePatterns containing extension, display name, etc. */ virtual FileTypePatterns getPatternsForType(const std::string& fileType) = 0; /** * Tries to find an icon file for the given extension. If not empty, * the returned string refers to a filename in the bitmaps/ folder. */ virtual std::string getIconForExtension(const std::string& extension) = 0; }; namespace filetype { // Some well-known file type constants const char* const TYPE_MAP = "map"; const char* const TYPE_MAP_EXPORT = "mapexport"; const char* const TYPE_PREFAB = "prefab"; const char* const TYPE_REGION = "region"; const char* const TYPE_MODEL_EXPORT = "modelexport"; const char* const TYPE_PAK = "pak"; } inline IFileTypeRegistry& GlobalFiletypes() { static module::InstanceReference _reference(MODULE_FILETYPES); return _reference; } ================================================ FILE: include/ifilter.h ================================================ #pragma once #include "imodule.h" #include "inode.h" #include "scene/filters/SceneFilter.h" #include #include const char* const MODULE_FILTERSYSTEM = "FilterSystem"; // Forward declaration class Entity; namespace filters { const char* const SELECT_OBJECTS_BY_FILTER_CMD = "SelectObjectsByFilter"; const char* const DESELECT_OBJECTS_BY_FILTER_CMD = "DeselectObjectsByFilter"; /** * @brief Interface for the FilterSystem * * The filter system provides a mechanism by which certain objects or materials * can be hidden from rendered views. * * The filter system operates an internal stack of system states, allowing the * current set of enabled filters to be saved and restored. */ class IFilterSystem: public RegisterableModule { public: /** * @brief Signal emitted when the state of filters has changed, filters have * been added or removed, or when rules have been altered. */ virtual sigc::signal filterConfigChangedSignal() const = 0; /** * @brief Signal emitted when filters are added, removed, or renamed. */ virtual sigc::signal filterCollectionChangedSignal() const = 0; /** * @brief Updates the "Filtered" status of all instances in the scenegraph * based on the current filter settings. */ virtual void update() = 0; /** * @brief Updates the specified subgraph, including the given node and all * its children, based on the current filter settings. * * @param root The root node of the subgraph to update. */ virtual void updateSubgraph(const scene::INodePtr& root) = 0; /** * @brief Visits all available filters and passes each filter's text name to * the provided visitor function. * * @param func A function object called with the filter name as an argument. */ virtual void forEachFilter(const std::function& func) = 0; /** * @brief Sets the state of the specified filter. * * @param filter The name of the filter to toggle. * @param state True to activate the filter, false to deactivate it. */ virtual void setFilterState(const std::string& filter, bool state) = 0; /** * @brief Retrieves the state of the specified filter. * * @param filter The name of the filter to query. * @return True if the filter is active, false otherwise. */ virtual bool getFilterState(const std::string& filter) const = 0; /** * @brief Duplicate the current filtersystem state and push it onto the * stack. * * The filtersystem state consists of the currently active filters. */ virtual void pushState() = 0; /// Pops the last filtersystem state from the stack and restores it. virtual void popState() = 0; /** * @brief Retrieves the event name associated with the specified filter. * * @param filter The name of the filter. * @return The event name of the filter. */ virtual std::string getFilterEventName(const std::string& filter) = 0; /** * @brief Tests whether a given item should be visible based on the * currently active filters. * * @param type The filter type to query. * @param name The string name of the item to query. * @return True if the item is visible, false otherwise. */ virtual bool isVisible(const FilterType type, const std::string& name) = 0; /** * @brief Tests whether a given entity should be visible based on the * currently active filters. * * @param entity The entity to test. * @return True if the entity is visible, false otherwise. */ virtual bool isEntityVisible(const Entity& entity) const = 0; // ===== API for Filter Management and Editing ===== /** * @brief Adds a new filter to the system with the specified ruleset. * The new filter is not set to read-only. * * @param filterName The name of the new filter. * @param ruleSet The ruleset to associate with the new filter. * @return True on success, false if the filter name already exists. */ virtual bool addFilter(const std::string& filterName, const FilterRules& ruleSet) = 0; /** * @brief Removes the specified filter. * * @param filter The name of the filter to remove. * @return True on success, false otherwise. */ virtual bool removeFilter(const std::string& filter) = 0; /** * @brief Renames the specified filter. This also updates the corresponding command * in the EventManager class. * * @param oldFilterName The current name of the filter. * @param newFilterName The new name for the filter. * @return True on success, false if the filter is not found or is read-only. */ virtual bool renameFilter(const std::string& oldFilterName, const std::string& newFilterName) = 0; /** * @brief Retrieves the ruleset associated with the specified filter. The * order of rules is important. * * @param filter The name of the filter. * @return The ruleset of the filter. */ virtual FilterRules getRuleSet(const std::string& filter) = 0; /** * @brief Replaces the existing ruleset of the specified filter with the * given criteria set. This applies only to non-read-only filters. * * @param filter The name of the filter. * @param ruleSet The new ruleset to apply. * @return True on success, false if the filter is not found or is read-only. */ virtual bool setFilterRules(const std::string& filter, const FilterRules& ruleSet) = 0; }; /// RAII class to push and pop filter state class ScopedFilterState { IFilterSystem& _filterSystem; public: ScopedFilterState(IFilterSystem& filterSystem): _filterSystem(filterSystem) { _filterSystem.pushState(); } ~ScopedFilterState() { _filterSystem.popState(); } }; } inline filters::IFilterSystem& GlobalFilterSystem() { static module::InstanceReference _reference(MODULE_FILTERSYSTEM); return _reference; } ================================================ FILE: include/ifonts.h ================================================ #pragma once #include "imodule.h" #include "irenderable.h" #include class Material; typedef std::shared_ptr MaterialPtr; namespace fonts { namespace q3font { // Default values of Quake 3 sourcecode. Don't change! const std::size_t GLYPH_COUNT_PER_FONT = 256; } // namespace // Container-class for Glyphs (== single font characters). class IGlyphInfo { public: int height; // number of scan lines int top; // top of glyph in buffer int bottom; // bottom of glyph in buffer int pitch; // width for copying int xSkip; // x adjustment int imageWidth; // width of actual image int imageHeight; // height of actual image float s; // x offset in image where glyph starts float t; // y offset in image where glyph starts float s2; float t2; std::string texture; // the texture name without extension, e.g. carleton_1_24 // The shader this glyph is associated with // this is NULL until the font is actually used ShaderPtr shader; }; typedef std::shared_ptr IGlyphInfoPtr; // Each D3 font has three resolutions enum Resolution { Resolution12, Resolution24, Resolution48, NumResolutions }; inline std::ostream& operator<< (std::ostream& os, Resolution res) { switch (res) { case Resolution12: os << "12"; break; case Resolution24: os << "24"; break; case Resolution48: os << "48"; break; default: assert(false); os << "Unrecognised"; break; } return os; } // Each font resolution has its own set of glyphs class IGlyphSet { public: virtual ~IGlyphSet() {} // 12, 24, 48 virtual Resolution getResolution() const = 0; // each set has 256 glyphs (q3font::GLYPH_COUNT_PER_FONT) virtual IGlyphInfoPtr getGlyph(std::size_t glyphIndex) const = 0; // Gets the scale for calculating the render font size virtual float getGlyphScale() const = 0; // Gets the maximum width of a glyph in this set virtual std::size_t getMaxGlyphWidth() const = 0; // Gets the maximum height of a glyph in this set virtual std::size_t getMaxGlyphHeight() const = 0; // Ensures that each glyph has a valid Shader virtual void realiseShaders() = 0; }; typedef std::shared_ptr IGlyphSetPtr; /** * Holds information about one specific font. * A font consists of three resolutions. */ class IFontInfo { public: virtual ~IFontInfo() {} // The name of the font, e.g. "carleton" virtual const std::string& getName() const = 0; // The language of this font virtual const std::string& getLanguage() const = 0; // Returns the glyphset for the specified resolution virtual IGlyphSetPtr getGlyphSet(Resolution resolution) = 0; }; typedef std::shared_ptr IFontInfoPtr; /** * greebo: Use the FontManager to load a specific font. The returned FontInfo structure * contains all the necessary info about the glyphs, as found in the font's DAT file. */ class IFontManager : public RegisterableModule { public: // Returns the info structure of a specific font (current language), // returns NULL if no font info is available yet virtual IFontInfoPtr findFontInfo(const std::string& name) = 0; }; } const char* const MODULE_FONTMANAGER("FontManager"); inline fonts::IFontManager& GlobalFontManager() { static module::InstanceReference _reference(MODULE_FONTMANAGER); return _reference; } ================================================ FILE: include/ifx.h ================================================ #pragma once #include "imodule.h" #include "ideclmanager.h" #include "math/Vector3.h" namespace fx { class IFxAction { public: using Ptr = std::shared_ptr; enum class Type { Undefined = -1, Light = 0, Particle, Decal, Model, Sound, Shake, AttachLight, AttachEntity, Launch, Shockwave }; virtual ~IFxAction() {} virtual Type getActionType() = 0; // Returns the name of this action (which might be an empty string) virtual const std::string& getName() = 0; // Returns the action delay in seconds virtual float getDelayInSeconds() = 0; // Action duration in seconds, before it is killed or restarted virtual float getDurationInSeconds() = 0; // True: Don't shake the entity this effect is attached to virtual bool getIgnoreMaster() = 0; // Shake parameters virtual float getShakeTimeInSeconds() = 0; virtual float getShakeAmplitude() = 0; virtual float getShakeDistance() = 0; virtual bool getShakeFalloff() = 0; virtual float getShakeImpulse() = 0; // True: The light in this effect doesn't cast shadows virtual bool getNoShadows() = 0; // Causes the sibling action to happen when this action does. virtual const std::string& getFireSiblingAction() = 0; // Let the delay be random between min and max (in seconds) // If both are 0.0 no random delay is active and the regular delay is used instead virtual std::pair getRandomDelay() = 0; // According to the docs this is not used virtual float getRotate() = 0; // Move around with the entity (vs stationary after spawning) virtual bool getTrackOrigin() = 0; // True: the action starts again after the 'duration' has run out virtual bool getRestart() = 0; // Fade in the RGB of the light or model over