Added miss

This commit is contained in:
Justin Marshall
2026-08-13 11:53:10 -07:00
parent ba32415d77
commit 58411f4e04
370 changed files with 104382 additions and 670 deletions
+12 -1
View File
@@ -6,6 +6,17 @@ YOU CAN RUN THE GAME WITHOUT THE SOURCE CODE RECREATION TO RUN THE EXPANSION PAC
You will need a copy of the retail game(you can buy it on steam).
## Building the reconstructed engine and game DLL
The build is centralized in `src/CMakeLists.txt`; it does not consume external
CSV source lists. From the repository root, run:
```powershell
Set-Location src
cmake --preset windows-x86-debug
cmake --build --preset windows-x86-debug --target q4_runtime
```
Come join us on discord!
https://discord.gg/y2hp2S8c9Y
@@ -20,4 +31,4 @@ https://github.com/jmarshall23
If you want to get ahold of me for work(I'm 16 year veteran of the game industry, just got laid off due to the AI surge),
specifically I do graphics engineering, port work, low level platform work, technical director work, complex gameplay code,
etc. I've worked on over 20 games or so, my e-mail address is justinmarshall20@gmail.com
etc. I've worked on over 20 games or so, my e-mail address is justinmarshall20@gmail.com
+779 -5
View File
@@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 3.25)
project(Quake4Reconstruction LANGUAGES C CXX)
get_filename_component(Q4_RUNTIME_DIR "${PROJECT_SOURCE_DIR}/.." ABSOLUTE)
if(NOT WIN32)
message(FATAL_ERROR "The initial reconstruction target is 32-bit Windows")
endif()
@@ -28,24 +30,796 @@ if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
endif()
# The build is intentionally defined in this file. CSV files under
# docs/reconstruction are provenance reports, not build inputs.
if(Q4_BUILD_IDLIB)
add_subdirectory(idlib)
# This is the exact first-party idlib compiland set recorded in quake4.pdb.
# Additional SDK files remain in the tree for the game DLLs but are not linked
# into the reconstructed executable until evidence assigns them to the target.
set(Q4_IDLIB_SOURCES
${PROJECT_SOURCE_DIR}/idlib/BitMsg.cpp
${PROJECT_SOURCE_DIR}/idlib/CmdArgs.cpp
${PROJECT_SOURCE_DIR}/idlib/Dict.cpp
${PROJECT_SOURCE_DIR}/idlib/Heap.cpp
${PROJECT_SOURCE_DIR}/idlib/LangDict.cpp
${PROJECT_SOURCE_DIR}/idlib/Lexer.cpp
${PROJECT_SOURCE_DIR}/idlib/LexerFactory.cpp
${PROJECT_SOURCE_DIR}/idlib/Lib.cpp
${PROJECT_SOURCE_DIR}/idlib/mapfile.cpp
${PROJECT_SOURCE_DIR}/idlib/Parser.cpp
${PROJECT_SOURCE_DIR}/idlib/Str.cpp
${PROJECT_SOURCE_DIR}/idlib/Timer.cpp
${PROJECT_SOURCE_DIR}/idlib/Token.cpp
${PROJECT_SOURCE_DIR}/idlib/bv/Bounds.cpp
${PROJECT_SOURCE_DIR}/idlib/bv/Box.cpp
${PROJECT_SOURCE_DIR}/idlib/bv/Frustum.cpp
${PROJECT_SOURCE_DIR}/idlib/bv/Sphere.cpp
${PROJECT_SOURCE_DIR}/idlib/containers/HashIndex.cpp
${PROJECT_SOURCE_DIR}/idlib/geometry/JointTransform.cpp
${PROJECT_SOURCE_DIR}/idlib/geometry/Surface.cpp
${PROJECT_SOURCE_DIR}/idlib/geometry/Surface_Patch.cpp
${PROJECT_SOURCE_DIR}/idlib/geometry/TraceModel.cpp
${PROJECT_SOURCE_DIR}/idlib/geometry/Winding.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Angles.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Math.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Matrix.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Plane.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Polynomial.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Quat.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Radians.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Rotation.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_3DNow.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_generic.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_MMX.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_SSE.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_SSE2.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Simd_SSE3.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Vector.cpp
${PROJECT_SOURCE_DIR}/idlib/hashing/CRC32.cpp
${PROJECT_SOURCE_DIR}/idlib/hashing/MD4.cpp
${PROJECT_SOURCE_DIR}/idlib/hashing/MD5.cpp
)
add_library(q4_idlib STATIC ${Q4_IDLIB_SOURCES})
target_include_directories(q4_idlib
PUBLIC
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/idlib
PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4_idlib
PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_RECON_ENGINE_PRIVATE
Q4_RECON_SDK_MSGQUEUE
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_precompile_headers(q4_idlib PRIVATE ${PROJECT_SOURCE_DIR}/idlib/precompiled.h)
set_target_properties(q4_idlib PROPERTIES
OUTPUT_NAME idlib
FOLDER "Engine"
)
# The Quake 4 SDK builds idlib a second time with Q4SDK for gamex86.dll.
# Several public classes (notably the SIMD hierarchy) are macro-sensitive, so
# linking the engine-private idlib into the game DLL gives the DLL a different
# vtable layout than the one seen by its game translation units.
set(Q4_GAME_IDLIB_SOURCES
${Q4_IDLIB_SOURCES}
${PROJECT_SOURCE_DIR}/idlib/geometry/Winding2D.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Lcp.cpp
${PROJECT_SOURCE_DIR}/idlib/math/Ode.cpp
)
add_library(q4_game_idlib STATIC ${Q4_GAME_IDLIB_SOURCES})
target_include_directories(q4_game_idlib
PUBLIC
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/idlib
PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4_game_idlib
PRIVATE
WIN32
_WINDOWS
_USE_32BIT_TIME_T
Q4SDK
Q4_NO_PUNKBUSTER
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_precompile_headers(q4_game_idlib PRIVATE ${PROJECT_SOURCE_DIR}/idlib/precompiled.h)
set_target_properties(q4_game_idlib PROPERTIES
OUTPUT_NAME game_idlib
FOLDER "Game"
)
endif()
if(Q4_BUILD_ENGINE_SEED)
add_subdirectory(engine)
function(q4_add_engine_object target)
add_library(${target} OBJECT ${ARGN})
target_include_directories(${target}
PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/renderer/jpeg-6
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis/include
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(${target}
PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_DISABLE_TOOLS
Q4_DISABLE_GL_LOGGING
Q4_DISABLE_TASKKEY_HOOK
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
set_target_properties(${target} PROPERTIES FOLDER "Engine/Seed")
endfunction()
file(GLOB_RECURSE Q4_AAS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/aas/*.cpp
)
set(Q4_AAS_FILE_SOURCE ${PROJECT_SOURCE_DIR}/aas/AASFile.cpp)
set(Q4_AAS_COMPILER_SOURCES
${PROJECT_SOURCE_DIR}/aas/AASSettingsTools.cpp
${PROJECT_SOURCE_DIR}/aas/AASTactical.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_file.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_gravity.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_ledge.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_merge.cpp
${PROJECT_SOURCE_DIR}/aas/AASCluster.cpp
${PROJECT_SOURCE_DIR}/aas/AASReach.cpp
${PROJECT_SOURCE_DIR}/aas/Brush.cpp
${PROJECT_SOURCE_DIR}/aas/BrushBSP.cpp
)
list(REMOVE_ITEM Q4_AAS_SOURCES ${Q4_AAS_COMPILER_SOURCES})
file(GLOB_RECURSE Q4_CM_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/cm/*.cpp
)
set(Q4_CM_MODEL_SOURCE ${PROJECT_SOURCE_DIR}/cm/CollisionModel.cpp)
set(Q4_CM_LOAD_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_load.cpp)
set(Q4_CM_CONTACTS_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_contacts.cpp)
set(Q4_CM_CONTENTS_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_contents.cpp)
set(Q4_CM_TRACE_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_trace.cpp)
set(Q4_CM_TRANSLATE_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_translate.cpp)
list(REMOVE_ITEM Q4_CM_SOURCES ${Q4_CM_MODEL_SOURCE})
file(GLOB Q4_FRAMEWORK_TOP_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/framework/*.cpp)
set(Q4_FRAMEWORK_PLAYER_MODEL_SOURCE ${PROJECT_SOURCE_DIR}/framework/DeclPlayerModel.cpp)
set(Q4_FRAMEWORK_ENGINE_TOP_SOURCES ${Q4_FRAMEWORK_TOP_SOURCES})
# DeclPlayerModel is owned by gamex86.dll in the retail PDB. Keep it out of
# q4xp.exe so the reconstructed compiland and its allocator live in the same
# module that registers DECL_PLAYER_MODEL.
list(REMOVE_ITEM Q4_FRAMEWORK_ENGINE_TOP_SOURCES ${Q4_FRAMEWORK_PLAYER_MODEL_SOURCE})
set(Q4_FRAMEWORK_SESSION_SOURCES
${PROJECT_SOURCE_DIR}/framework/common.cpp
${PROJECT_SOURCE_DIR}/framework/session.cpp
${PROJECT_SOURCE_DIR}/framework/session_menu.cpp
)
set(Q4_FRAMEWORK_EDITFIELD_SOURCE ${PROJECT_SOURCE_DIR}/framework/editfield.cpp)
set(Q4_FRAMEWORK_CONSOLE_SOURCE ${PROJECT_SOURCE_DIR}/framework/console.cpp)
set(Q4_FRAMEWORK_USERCMD_SOURCE ${PROJECT_SOURCE_DIR}/framework/usercmdgen.cpp)
set(Q4_FRAMEWORK_CONSOLE_SOURCES
${Q4_FRAMEWORK_EDITFIELD_SOURCE}
${Q4_FRAMEWORK_CONSOLE_SOURCE}
${Q4_FRAMEWORK_USERCMD_SOURCE}
)
file(GLOB Q4_FRAMEWORK_ASYNC_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/framework/async/*.cpp)
set(Q4_FRAMEWORK_MSGCHANNEL_SOURCE ${PROJECT_SOURCE_DIR}/framework/async/msgchannel.cpp)
list(REMOVE_ITEM Q4_FRAMEWORK_ASYNC_SOURCES ${Q4_FRAMEWORK_MSGCHANNEL_SOURCE})
set(Q4_FRAMEWORK_CORE_SOURCES ${Q4_FRAMEWORK_ENGINE_TOP_SOURCES})
list(REMOVE_ITEM Q4_FRAMEWORK_CORE_SOURCES
${Q4_FRAMEWORK_SESSION_SOURCES}
${Q4_FRAMEWORK_CONSOLE_SOURCES}
)
file(GLOB_RECURSE Q4_UI_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/ui/*.cpp
)
# Retail quake4.exe renderer compilation units. Keep this explicit: the PDB
# records one object for each entry and the list doubles as a boundary audit.
set(Q4_RENDERER_SOURCES
${PROJECT_SOURCE_DIR}/renderer/Cinematic.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_arb.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_arb2.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_common.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_nv10.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_nv20.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_r200.cpp
${PROJECT_SOURCE_DIR}/renderer/GuiModel.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_files.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_init.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_load.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_process.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_program.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_stats.cpp
${PROJECT_SOURCE_DIR}/renderer/Interaction.cpp
${PROJECT_SOURCE_DIR}/renderer/Material.cpp
${PROJECT_SOURCE_DIR}/renderer/MegaTexture.cpp
${PROJECT_SOURCE_DIR}/renderer/Model.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelDecal.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelManager.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelOverlay.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_ase.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_beam.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_liquid.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_lwo.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_ma.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_md3.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_md5.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_sprite.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderEntity.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderSystem.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderSystem_init.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_demo.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_load.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_portals.cpp
${PROJECT_SOURCE_DIR}/renderer/Shaders.cpp
${PROJECT_SOURCE_DIR}/renderer/rvGLSLShader.cpp
${PROJECT_SOURCE_DIR}/renderer/rvIndexBuffer.cpp
${PROJECT_SOURCE_DIR}/renderer/rvMesh.cpp
${PROJECT_SOURCE_DIR}/renderer/rvPrimBatch.cpp
${PROJECT_SOURCE_DIR}/renderer/rvRenderModelMD5R.cpp
${PROJECT_SOURCE_DIR}/renderer/rvSpecial.cpp
${PROJECT_SOURCE_DIR}/renderer/rvTexRenderTarget.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexBuffer.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexBufferCopy.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexFormat.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_backend.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_deform.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_font.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_guisurf.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_light.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_lightrun.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_main.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_orderIndexes.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_polytope.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_render.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_rendertools.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_shadowbounds.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_stencilshadow.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_subview.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_trace.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_trisurf.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_turboshadow.cpp
${PROJECT_SOURCE_DIR}/renderer/VertexCache.cpp
)
# Retail BSE object boundaries recovered from quake4.pdb.
set(Q4_BSE_SOURCES
${PROJECT_SOURCE_DIR}/bse/BSE_Bounds.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Effect.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_EffectTemplate.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Electricity.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Envelopes.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Light.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Manager.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_ParseParticle2.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Particle.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Render.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Segment.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_SegmentTemplate.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_SpawnDomains.cpp
)
file(GLOB Q4_JPEG_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/renderer/jpeg-6/*.c)
file(GLOB_RECURSE Q4_SOUND_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/sound/*.cpp)
file(GLOB_RECURSE Q4_OGGVORBIS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/sound/OggVorbis/*.c
)
file(GLOB_RECURSE Q4_SYS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/sys/*.cpp
)
q4_add_engine_object(q4_engine_aas_file ${Q4_AAS_FILE_SOURCE})
q4_add_engine_object(q4_engine_aas ${Q4_AAS_SOURCES})
target_compile_definitions(q4_engine_aas PRIVATE Q4_AAS_LEGACY_SEED)
q4_add_engine_object(q4_engine_cm_model ${Q4_CM_MODEL_SOURCE})
target_compile_definitions(q4_engine_cm_model PRIVATE Q4_CM_MODEL_ONLY)
q4_add_engine_object(q4_engine_cm_load ${Q4_CM_LOAD_SOURCE})
q4_add_engine_object(q4_engine_cm_contacts ${Q4_CM_CONTACTS_SOURCE})
q4_add_engine_object(q4_engine_cm_contents ${Q4_CM_CONTENTS_SOURCE})
q4_add_engine_object(q4_engine_cm_trace ${Q4_CM_TRACE_SOURCE})
q4_add_engine_object(q4_engine_cm_translate ${Q4_CM_TRANSLATE_SOURCE})
q4_add_engine_object(q4_engine_cm_seed ${Q4_CM_SOURCES})
target_compile_definitions(q4_engine_cm_seed PRIVATE Q4_CM_LEGACY_SEED)
set(Q4_FRAMEWORK_CORE_TARGETS)
foreach(source IN LISTS Q4_FRAMEWORK_CORE_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_framework_core_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_FRAMEWORK_CORE_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_framework_core DEPENDS ${Q4_FRAMEWORK_CORE_TARGETS})
set_target_properties(q4_engine_framework_core PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_engine_framework_editfield ${Q4_FRAMEWORK_EDITFIELD_SOURCE})
q4_add_engine_object(q4_engine_framework_console_impl ${Q4_FRAMEWORK_CONSOLE_SOURCE})
q4_add_engine_object(q4_engine_framework_usercmd ${Q4_FRAMEWORK_USERCMD_SOURCE})
add_custom_target(q4_engine_framework_console
DEPENDS
q4_engine_framework_editfield
q4_engine_framework_console_impl
q4_engine_framework_usercmd
)
set_target_properties(q4_engine_framework_console PROPERTIES FOLDER "Engine/Seed")
set(Q4_FRAMEWORK_ASYNC_TARGETS)
foreach(source IN LISTS Q4_FRAMEWORK_ASYNC_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_framework_async_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_FRAMEWORK_ASYNC_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_framework_async DEPENDS ${Q4_FRAMEWORK_ASYNC_TARGETS})
set_target_properties(q4_engine_framework_async PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_engine_framework_msgchannel ${Q4_FRAMEWORK_MSGCHANNEL_SOURCE})
target_compile_definitions(q4_engine_framework_msgchannel PRIVATE Q4_RECON_SDK_MSGQUEUE)
q4_add_engine_object(q4_engine_framework_session ${Q4_FRAMEWORK_SESSION_SOURCES})
foreach(target q4_engine_framework_editfield q4_engine_framework_console_impl q4_engine_framework_usercmd q4_engine_framework_session)
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
endforeach()
set(Q4_UI_TARGETS)
foreach(source IN LISTS Q4_UI_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_ui_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_UI_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_ui DEPENDS ${Q4_UI_TARGETS})
set_target_properties(q4_engine_ui PROPERTIES FOLDER "Engine/Seed")
set(Q4_RENDERER_TARGETS)
foreach(source IN LISTS Q4_RENDERER_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_renderer_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_RENDERER_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_renderer DEPENDS ${Q4_RENDERER_TARGETS})
set_target_properties(q4_engine_renderer PROPERTIES FOLDER "Engine/Seed")
set(Q4_BSE_TARGETS)
foreach(source IN LISTS Q4_BSE_SOURCES)
get_filename_component(stem ${source} NAME_WE)
string(TOLOWER ${stem} stem_lower)
set(target q4_engine_bse_${stem_lower})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_BSE_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_bse DEPENDS ${Q4_BSE_TARGETS})
set_target_properties(q4_engine_bse PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_bse_abi ${PROJECT_SOURCE_DIR}/tests/abi/BSE_ABI.cpp)
target_compile_definitions(q4_bse_abi PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
set_target_properties(q4_bse_abi PROPERTIES FOLDER "Reconstruction/ABI")
q4_add_engine_object(q4_renderer_raven_abi ${PROJECT_SOURCE_DIR}/tests/abi/RendererRaven_ABI.cpp)
target_compile_definitions(q4_renderer_raven_abi PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
set_target_properties(q4_renderer_raven_abi PROPERTIES FOLDER "Reconstruction/ABI")
q4_add_engine_object(q4_thirdparty_jpeg ${Q4_JPEG_SOURCES})
target_include_directories(q4_thirdparty_jpeg PRIVATE ${PROJECT_SOURCE_DIR}/renderer/jpeg-6)
set_target_properties(q4_thirdparty_jpeg PROPERTIES FOLDER "ThirdParty")
set(Q4_SOUND_TARGETS)
foreach(source IN LISTS Q4_SOUND_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_sound_${stem})
q4_add_engine_object(${target} ${source})
target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}/sound ${PROJECT_SOURCE_DIR}/sys/win32)
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE Q4_RECONSTRUCTED_SOUND)
list(APPEND Q4_SOUND_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_sound DEPENDS ${Q4_SOUND_TARGETS})
set_target_properties(q4_engine_sound PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_thirdparty_oggvorbis ${Q4_OGGVORBIS_SOURCES})
target_include_directories(q4_thirdparty_oggvorbis PRIVATE
${PROJECT_SOURCE_DIR}/sound/OggVorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbissrc
)
set_target_properties(q4_thirdparty_oggvorbis PROPERTIES FOLDER "ThirdParty")
set(Q4_SYS_TARGETS)
foreach(source IN LISTS Q4_SYS_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_sys_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_SYS_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_sys DEPENDS ${Q4_SYS_TARGETS})
set_target_properties(q4_engine_sys PROPERTIES FOLDER "Engine/Seed")
add_custom_target(q4_engine_seed
DEPENDS
q4_engine_aas
q4_engine_aas_file
q4_engine_cm_model
q4_engine_cm_load
q4_engine_cm_contacts
q4_engine_cm_contents
q4_engine_cm_trace
q4_engine_cm_translate
q4_engine_cm_seed
q4_engine_framework_core
q4_engine_framework_console
q4_engine_framework_async
q4_engine_framework_msgchannel
q4_engine_framework_session
q4_engine_ui
q4_engine_renderer
q4_engine_bse
q4_thirdparty_jpeg
q4_engine_sound
q4_thirdparty_oggvorbis
q4_engine_sys
)
set_target_properties(q4_engine_seed PROPERTIES FOLDER "Engine")
add_custom_target(q4_reconstruction_foundation
DEPENDS
q4_idlib
q4_engine_aas
q4_engine_aas_file
q4_engine_cm_model
q4_engine_cm_load
q4_engine_cm_contacts
q4_engine_cm_contents
q4_engine_cm_trace
q4_engine_cm_translate
q4_engine_cm_seed
q4_engine_framework_console
q4_engine_framework_core_cmdsystem
q4_engine_framework_core_compressor
q4_engine_framework_core_cvarsystem
q4_engine_framework_core_declaf
q4_engine_framework_core_declentitydef
q4_engine_framework_core_declmanager
q4_engine_framework_core_declpda
q4_engine_framework_core_declskin
q4_engine_framework_core_decltable
q4_engine_framework_core_demofile
q4_engine_framework_core_eventloop
q4_engine_framework_core_file
q4_engine_framework_core_filesystem
q4_engine_framework_core_keyinput
q4_engine_framework_core_unzip
q4_engine_framework_async_asyncnetwork
q4_engine_framework_async_networksystem
q4_engine_framework_msgchannel
q4_engine_ui
q4_thirdparty_jpeg
q4_thirdparty_oggvorbis
)
set_target_properties(q4_reconstruction_foundation PROPERTIES FOLDER "Reconstruction")
# Full reconstructed Win32 engine integration target. The per-compiland
# object targets above remain the source-ownership/ABI audit surface; this
# target compiles the same recovered sources into a runnable executable.
# The editor and compilers live in the external q4_tools target and cross the
# reconstructed retail Tools API rather than being compiled into the engine.
# CURL remains disabled at this reconstruction frontier.
set(Q4_OPENAL_LOADER_SOURCES
${PROJECT_SOURCE_DIR}/openal/idal.cpp
)
add_executable(q4xp WIN32
${PROJECT_SOURCE_DIR}/sys/win32/rc/Quake4.rc
${Q4_AAS_SOURCES}
${Q4_CM_MODEL_SOURCE}
${Q4_CM_SOURCES}
${Q4_FRAMEWORK_ENGINE_TOP_SOURCES}
${Q4_FRAMEWORK_ASYNC_SOURCES}
${Q4_FRAMEWORK_MSGCHANNEL_SOURCE}
${Q4_UI_SOURCES}
${Q4_RENDERER_SOURCES}
${Q4_BSE_SOURCES}
${Q4_JPEG_SOURCES}
${Q4_SOUND_SOURCES}
${Q4_OGGVORBIS_SOURCES}
${Q4_OPENAL_LOADER_SOURCES}
${Q4_SYS_SOURCES}
)
target_include_directories(q4xp PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/renderer/jpeg-6
${PROJECT_SOURCE_DIR}/sound
${PROJECT_SOURCE_DIR}/sys/win32
${PROJECT_SOURCE_DIR}/sound/OggVorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbissrc
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4xp PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
__DOOM_DLL__
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_RECON_ENGINE_PRIVATE
Q4_RECON_SDK_MSGQUEUE
Q4_DISABLE_TASKKEY_HOOK
Q4_DISABLE_TOOLS
Q4_DISABLE_GL_LOGGING
Q4_RECONSTRUCTED_SOUND
ID_ENABLE_CURL=0
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_link_directories(q4xp PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Lib/x86"
${PROJECT_SOURCE_DIR}/openal/lib
)
target_link_libraries(q4xp PRIVATE
q4_idlib
opengl32
winmm
ws2_32
iphlpapi
dbghelp
comctl32
dinput8
dsound
dxguid
version
)
if(MSVC)
# Keep an address map and symbols beside the reconstructed executable so
# retail-startup crashes can be resolved without enabling the tools DLL.
target_compile_options(q4xp PRIVATE /Zi)
target_link_options(q4xp PRIVATE
/DEBUG:FULL
/PDB:${Q4_RUNTIME_DIR}/q4xp.pdb
/MAP:${Q4_RUNTIME_DIR}/q4xp.map
/STACK:16777216,4096
)
endif()
set_target_properties(q4xp PROPERTIES
OUTPUT_NAME q4xp
RUNTIME_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${Q4_RUNTIME_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${Q4_RUNTIME_DIR}"
PDB_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}"
FOLDER "Engine"
)
endif()
if(Q4_BUILD_GAME_DLL)
add_subdirectory(game)
file(GLOB_RECURSE Q4_GAME_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/game/*.cpp
)
# Callbacks.cpp is generated-style source text included by gamesys/Class.cpp;
# it is not a standalone translation unit in the Quake 4 SDK project.
list(REMOVE_ITEM Q4_GAME_SOURCES
${PROJECT_SOURCE_DIR}/game/gamesys/Callbacks.cpp
)
add_library(gamex86 SHARED
${Q4_GAME_SOURCES}
${PROJECT_SOURCE_DIR}/framework/DeclPlayerModel.cpp
)
target_include_directories(gamex86 PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/game
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(gamex86 PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
GAME_DLL
Q4SDK
Q4_RECON_RETAIL_UI_MANAGER_ABI
Q4_NO_PUNKBUSTER
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_link_libraries(gamex86 PRIVATE q4_game_idlib winmm)
if(MSVC)
target_compile_options(gamex86 PRIVATE /Zi)
target_link_options(gamex86 PRIVATE
/DEF:${PROJECT_SOURCE_DIR}/game/game.def
/DEBUG:FULL
/PDB:${Q4_RUNTIME_DIR}/q4base/gamex86.pdb
)
endif()
set_target_properties(gamex86 PROPERTIES
OUTPUT_NAME gamex86
PREFIX ""
RUNTIME_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}/q4base"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "${Q4_RUNTIME_DIR}/q4base"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${Q4_RUNTIME_DIR}/q4base"
LIBRARY_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}/q4base"
ARCHIVE_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}/q4base"
PDB_OUTPUT_DIRECTORY "${Q4_RUNTIME_DIR}/q4base"
FOLDER "Game"
)
endif()
if(Q4_BUILD_ENGINE_SEED AND Q4_BUILD_GAME_DLL)
add_custom_target(q4_runtime
DEPENDS
q4xp
gamex86
)
set_target_properties(q4_runtime PROPERTIES FOLDER "Runtime")
endif()
if(Q4_BUILD_TOOLS_DLL)
add_subdirectory(tools)
file(GLOB Q4_RADIANT_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/tools/radiant/*.cpp
${PROJECT_SOURCE_DIR}/tools/common/*.cpp
${PROJECT_SOURCE_DIR}/tools/comafx/*.cpp
)
set_source_files_properties(${Q4_RADIANT_SOURCES} PROPERTIES
COMPILE_OPTIONS "/FI${PROJECT_SOURCE_DIR}/tools/comafx/StdAfx.h"
)
add_library(q4_tools SHARED
${PROJECT_SOURCE_DIR}/tools/ToolsStub.cpp
${PROJECT_SOURCE_DIR}/tools/ToolRenderAdapters.cpp
${PROJECT_SOURCE_DIR}/tools/Toolsx86.def
${PROJECT_SOURCE_DIR}/sys/win32/rc/Radiant.rc
${PROJECT_SOURCE_DIR}/sys/win32/rc/Common.rc
${PROJECT_SOURCE_DIR}/sys/win32/rc/PropTree.rc
${PROJECT_SOURCE_DIR}/idlib/geometry/Surface_SweptSpline.cpp
${PROJECT_SOURCE_DIR}/aas/AASSettingsTools.cpp
${PROJECT_SOURCE_DIR}/aas/AASTactical.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_file.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_gravity.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_ledge.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_merge.cpp
${PROJECT_SOURCE_DIR}/aas/AASCluster.cpp
${PROJECT_SOURCE_DIR}/aas/AASReach.cpp
${PROJECT_SOURCE_DIR}/aas/Brush.cpp
${PROJECT_SOURCE_DIR}/aas/BrushBSP.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/dmap.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/facebsp.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/gldraw.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/glfile.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/leakfile.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/map.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/optimize.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/optimize_gcc.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/output.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/portals.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/shadowopt3.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/tritjunction.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/tritools.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/ubrush.cpp
${PROJECT_SOURCE_DIR}/tools/compilers/dmap/usurface.cpp
${Q4_RADIANT_SOURCES}
)
if(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION)
target_include_directories(q4_tools BEFORE PRIVATE
"C:/Program Files (x86)/Windows Kits/10/Include/${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}/shared"
)
endif()
target_include_directories(q4_tools PRIVATE
${PROJECT_SOURCE_DIR}
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4_tools PRIVATE
WIN32
_WINDOWS
ID_GL_HARDLINK
_LOAD_DLL
Q4_NO_PUNKBUSTER
Q4_RECON_ENGINE_PRIVATE
Q4_RECON_SDK_MSGQUEUE
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_link_libraries(q4_tools PRIVATE
q4_idlib
user32
gdi32
comctl32
comdlg32
shell32
opengl32
glu32
ws2_32
)
set_target_properties(q4_tools PROPERTIES
OUTPUT_NAME Toolsx86
PREFIX ""
FOLDER "Tools"
MFC_FLAG 2
)
# Keep the 2005 retail Toolsx86.dll intact for binary comparison. The
# reconstructed engine deliberately loads this non-conflicting runtime alias.
add_custom_command(TARGET q4_tools POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
$<TARGET_FILE:q4_tools>
"${Q4_RUNTIME_DIR}/ToolsReconstructedx86.dll"
)
endif()
if(Q4_BUILD_RECON_TOOLS)
add_subdirectory(tools/reconstruction)
add_custom_target(reconstruction_manifests SOURCES
${PROJECT_SOURCE_DIR}/tools/reconstruction/Export-EvidenceManifest.ps1
${PROJECT_SOURCE_DIR}/tools/reconstruction/Export-ReconstructionLedger.ps1
${PROJECT_SOURCE_DIR}/tools/reconstruction/Seed-DoomImplementations.ps1
${PROJECT_SOURCE_DIR}/tools/reconstruction/Seed-DoomHeaders.ps1
)
set_target_properties(reconstruction_manifests PROPERTIES FOLDER "Reconstruction")
if(MSVC)
set(DIA_SDK_ROOT "${CMAKE_GENERATOR_INSTANCE}/DIA SDK")
if(EXISTS "${DIA_SDK_ROOT}/include/dia2.h")
add_executable(q4_pdb_inventory
${PROJECT_SOURCE_DIR}/tools/reconstruction/pdb_inventory.cpp
)
target_include_directories(q4_pdb_inventory PRIVATE "${DIA_SDK_ROOT}/include")
target_link_directories(q4_pdb_inventory PRIVATE "${DIA_SDK_ROOT}/lib")
target_link_libraries(q4_pdb_inventory PRIVATE diaguids ole32 oleaut32)
target_compile_definitions(q4_pdb_inventory PRIVATE UNICODE _UNICODE)
set_target_properties(q4_pdb_inventory PROPERTIES FOLDER "Reconstruction")
else()
message(WARNING "DIA SDK not found; q4_pdb_inventory will not be built")
endif()
endif()
endif()
enable_testing()
+1031
View File
File diff suppressed because it is too large Load Diff
+485
View File
@@ -0,0 +1,485 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASBuild_local.h"
#define VERTEX_HASH_BOXSIZE (1<<6) // must be power of 2
#define VERTEX_HASH_SIZE (VERTEX_HASH_BOXSIZE*VERTEX_HASH_BOXSIZE)
#define EDGE_HASH_SIZE (1<<14)
#define INTEGRAL_EPSILON 0.01f
#define VERTEX_EPSILON 0.1f
#define AAS_PLANE_NORMAL_EPSILON 0.00001f
#define AAS_PLANE_DIST_EPSILON 0.01f
idHashIndex *aas_vertexHash;
idHashIndex *aas_edgeHash;
idBounds aas_vertexBounds;
int aas_vertexShift;
/*
================
idAASBuild::SetupHash
================
*/
void idAASBuild::SetupHash( void ) {
aas_vertexHash = new idHashIndex( VERTEX_HASH_SIZE, 1024 );
aas_edgeHash = new idHashIndex( EDGE_HASH_SIZE, 1024 );
}
/*
================
idAASBuild::ShutdownHash
================
*/
void idAASBuild::ShutdownHash( void ) {
delete aas_vertexHash;
delete aas_edgeHash;
}
/*
================
idAASBuild::ClearHash
================
*/
void idAASBuild::ClearHash( const idBounds &bounds ) {
int i;
float f, max;
aas_vertexHash->Clear();
aas_edgeHash->Clear();
aas_vertexBounds = bounds;
max = bounds[1].x - bounds[0].x;
f = bounds[1].y - bounds[0].y;
if ( f > max ) {
max = f;
}
aas_vertexShift = (float) max / VERTEX_HASH_BOXSIZE;
for ( i = 0; (1<<i) < aas_vertexShift; i++ ) {
}
if ( i == 0 ) {
aas_vertexShift = 1;
}
else {
aas_vertexShift = i;
}
}
/*
================
idAASBuild::HashVec
================
*/
ID_INLINE int idAASBuild::HashVec( const idVec3 &vec ) {
int x, y;
x = (((int) (vec[0] - aas_vertexBounds[0].x + 0.5)) + 2) >> 2;
y = (((int) (vec[1] - aas_vertexBounds[0].y + 0.5)) + 2) >> 2;
return (x + y * VERTEX_HASH_BOXSIZE) & (VERTEX_HASH_SIZE-1);
}
/*
================
idAASBuild::GetVertex
================
*/
bool idAASBuild::GetVertex( const idVec3 &v, int *vertexNum ) {
int i, hashKey, vn;
aasVertex_t vert, *p;
for (i = 0; i < 3; i++) {
if ( idMath::Fabs(v[i] - idMath::Rint(v[i])) < INTEGRAL_EPSILON ) {
vert[i] = idMath::Rint(v[i]);
}
else {
vert[i] = v[i];
}
}
hashKey = idAASBuild::HashVec( vert );
for ( vn = aas_vertexHash->First( hashKey ); vn >= 0; vn = aas_vertexHash->Next( vn ) ) {
p = &file->vertices[vn];
// first compare z-axis because hash is based on x-y plane
if (idMath::Fabs( vert.z - p->z ) < VERTEX_EPSILON &&
idMath::Fabs( vert.x - p->x ) < VERTEX_EPSILON &&
idMath::Fabs( vert.y - p->y ) < VERTEX_EPSILON )
{
*vertexNum = vn;
return true;
}
}
*vertexNum = file->vertices.Num();
aas_vertexHash->Add( hashKey, file->vertices.Num() );
file->vertices.Append( vert );
return false;
}
/*
================
idAASBuild::GetEdge
================
*/
bool idAASBuild::GetEdge( const idVec3 &v1, const idVec3 &v2, int *edgeNum, int v1num ) {
int v2num, hashKey, e;
int *vertexNum;
aasEdge_t edge;
bool found;
if ( v1num != -1 ) {
found = true;
}
else {
found = GetVertex( v1, &v1num );
}
found &= GetVertex( v2, &v2num );
// if both vertexes are the same or snapped onto each other
if ( v1num == v2num ) {
*edgeNum = 0;
return true;
}
hashKey = aas_edgeHash->GenerateKey( v1num, v2num );
// if both vertexes where already stored
if ( found ) {
for ( e = aas_edgeHash->First( hashKey ); e >= 0; e = aas_edgeHash->Next( e ) ) {
vertexNum = file->edges[e].vertexNum;
if ( vertexNum[0] == v2num ) {
if ( vertexNum[1] == v1num ) {
// negative for a reversed edge
*edgeNum = -e;
break;
}
}
else if ( vertexNum[0] == v1num ) {
if ( vertexNum[1] == v2num ) {
*edgeNum = e;
break;
}
}
}
// if edge found in hash
if ( e >= 0 ) {
return true;
}
}
*edgeNum = file->edges.Num();
aas_edgeHash->Add( hashKey, file->edges.Num() );
edge.vertexNum[0] = v1num;
edge.vertexNum[1] = v2num;
file->edges.Append( edge );
return false;
}
/*
================
idAASBuild::GetFaceForPortal
================
*/
bool idAASBuild::GetFaceForPortal( idBrushBSPPortal *portal, int side, int *faceNum ) {
int i, j, v1num;
int numFaceEdges, faceEdges[MAX_POINTS_ON_WINDING];
idWinding *w;
aasFace_t face;
if ( portal->GetFaceNum() > 0 ) {
if ( side ) {
*faceNum = -portal->GetFaceNum();
}
else {
*faceNum = portal->GetFaceNum();
}
return true;
}
w = portal->GetWinding();
// turn the winding into a sequence of edges
numFaceEdges = 0;
v1num = -1; // first vertex unknown
for ( i = 0; i < w->GetNumPoints(); i++ ) {
GetEdge( (*w)[i].ToVec3(), (*w)[(i+1)%w->GetNumPoints()].ToVec3(), &faceEdges[numFaceEdges], v1num );
if ( faceEdges[numFaceEdges] ) {
// last vertex of this edge is the first vertex of the next edge
v1num = file->edges[ abs(faceEdges[numFaceEdges]) ].vertexNum[ INTSIGNBITNOTSET(faceEdges[numFaceEdges]) ];
// this edge is valid so keep it
numFaceEdges++;
}
}
// should have at least 3 edges
if ( numFaceEdges < 3 ) {
return false;
}
// the polygon is invalid if some edge is found twice
for ( i = 0; i < numFaceEdges; i++ ) {
for ( j = i+1; j < numFaceEdges; j++ ) {
if ( faceEdges[i] == faceEdges[j] || faceEdges[i] == -faceEdges[j] ) {
return false;
}
}
}
portal->SetFaceNum( file->faces.Num() );
face.planeNum = file->planeList.FindPlane( portal->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
face.flags = portal->GetFlags();
face.areas[0] = face.areas[1] = 0;
face.firstEdge = file->edgeIndex.Num();
face.numEdges = numFaceEdges;
for ( i = 0; i < numFaceEdges; i++ ) {
file->edgeIndex.Append( faceEdges[i] );
}
if ( side ) {
*faceNum = -file->faces.Num();
}
else {
*faceNum = file->faces.Num();
}
file->faces.Append( face );
return true;
}
/*
================
idAASBuild::GetAreaForLeafNode
================
*/
bool idAASBuild::GetAreaForLeafNode( idBrushBSPNode *node, int *areaNum ) {
int s, faceNum;
idBrushBSPPortal *p;
aasArea_t area;
if ( node->GetAreaNum() ) {
*areaNum = -node->GetAreaNum();
return true;
}
area.flags = node->GetFlags();
area.cluster = area.clusterAreaNum = 0;
area.contents = node->GetContents();
area.firstFace = file->faceIndex.Num();
area.numFaces = 0;
area.reach = NULL;
area.rev_reach = NULL;
for ( p = node->GetPortals(); p; p = p->Next(s) ) {
s = (p->GetNode(1) == node);
if ( !GetFaceForPortal( p, s, &faceNum ) ) {
continue;
}
file->faceIndex.Append( faceNum );
area.numFaces++;
if ( faceNum > 0 ) {
file->faces[abs(faceNum)].areas[0] = file->areas.Num();
}
else {
file->faces[abs(faceNum)].areas[1] = file->areas.Num();
}
}
if ( !area.numFaces ) {
*areaNum = 0;
return false;
}
*areaNum = -file->areas.Num();
node->SetAreaNum( file->areas.Num() );
file->areas.Append( area );
DisplayRealTimeString( "\r%6d", file->areas.Num() );
return true;
}
/*
================
idAASBuild::StoreTree_r
================
*/
int idAASBuild::StoreTree_r( idBrushBSPNode *node ) {
int areaNum, nodeNum, child0, child1;
aasNode_t aasNode;
if ( !node ) {
return 0;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return 0;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
if ( GetAreaForLeafNode( node, &areaNum ) ) {
return areaNum;
}
return 0;
}
aasNode.planeNum = file->planeList.FindPlane( node->GetPlane(), AAS_PLANE_NORMAL_EPSILON, AAS_PLANE_DIST_EPSILON );
aasNode.children[0] = aasNode.children[1] = 0;
nodeNum = file->nodes.Num();
file->nodes.Append( aasNode );
// !@#$%^ cause of some bug we cannot set the children directly with the StoreTree_r return value
child0 = StoreTree_r( node->GetChild(0) );
file->nodes[nodeNum].children[0] = child0;
child1 = StoreTree_r( node->GetChild(1) );
file->nodes[nodeNum].children[1] = child1;
if ( !child0 && !child1 ) {
file->nodes.SetNum( file->nodes.Num()-1 );
return 0;
}
return nodeNum;
}
/*
================
idAASBuild::GetSizeEstimate_r
================
*/
void idAASBuild::GetSizeEstimate_r( idBrushBSPNode *parent, idBrushBSPNode *node, struct sizeEstimate_s &size ) {
idBrushBSPPortal *p;
int s;
if ( !node ) {
return;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
// multiple branches of the bsp tree might point to the same leaf node
if ( node->GetParent() == parent ) {
size.numAreas++;
for ( p = node->GetPortals(); p; p = p->Next(s) ) {
s = (p->GetNode(1) == node);
size.numFaceIndexes++;
size.numEdgeIndexes += p->GetWinding()->GetNumPoints();
}
}
}
else {
size.numNodes++;
}
GetSizeEstimate_r( node, node->GetChild(0), size );
GetSizeEstimate_r( node, node->GetChild(1), size );
}
/*
================
idAASBuild::SetSizeEstimate
================
*/
void idAASBuild::SetSizeEstimate( const idBrushBSP &bsp, idAASCompilerFile *file ) {
sizeEstimate_t size;
size.numEdgeIndexes = 1;
size.numFaceIndexes = 1;
size.numAreas = 1;
size.numNodes = 1;
GetSizeEstimate_r( NULL, bsp.GetRootNode(), size );
file->SetSizes( size );
}
/*
================
idAASBuild::StoreFile
================
*/
bool idAASBuild::StoreFile( const idBrushBSP &bsp ) {
aasEdge_t edge;
aasFace_t face;
aasArea_t area;
aasNode_t node;
common->Printf( "[Store AAS]\n" );
SetupHash();
ClearHash( bsp.GetTreeBounds() );
file = new idAASCompilerFile( AASFile->CreateNew() );
file->Clear();
SetSizeEstimate( bsp, file );
// the first edge is a dummy
memset( &edge, 0, sizeof( edge ) );
file->edges.Append( edge );
// the first face is a dummy
memset( &face, 0, sizeof( face ) );
file->faces.Append( face );
// the first area is a dummy
memset( &area, 0, sizeof( area ) );
file->areas.Append( area );
// the first node is a dummy
memset( &node, 0, sizeof( node ) );
file->nodes.Append( node );
// store the tree
StoreTree_r( bsp.GetRootNode() );
// calculate area bounds and a reachable point in the area
file->FinishAreas();
ShutdownHash();
common->Printf( "\r%6d areas\n", file->areas.Num() );
return true;
}
+359
View File
@@ -0,0 +1,359 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASBuild_local.h"
/*
============
idAASBuild::SetPortalFlags_r
============
*/
void idAASBuild::SetPortalFlags_r( idBrushBSPNode *node ) {
int s;
idBrushBSPPortal *p;
idVec3 normal;
if ( !node ) {
return;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
for ( p = node->GetPortals(); p; p = p->Next(s) ) {
s = (p->GetNode(1) == node);
// if solid at the other side of the portal
if ( p->GetNode(!s)->GetContents() & AREACONTENTS_SOLID ) {
if ( s ) {
normal = -p->GetPlane().Normal();
}
else {
normal = p->GetPlane().Normal();
}
if ( normal * aasSettings->invGravityDir > aasSettings->minFloorCos ) {
p->SetFlag( FACE_FLOOR );
}
else {
p->SetFlag( FACE_SOLID );
}
}
}
return;
}
SetPortalFlags_r( node->GetChild(0) );
SetPortalFlags_r( node->GetChild(1) );
}
/*
============
idAASBuild::PortalIsGap
============
*/
bool idAASBuild::PortalIsGap( idBrushBSPPortal *portal, int side ) {
idVec3 normal;
// if solid at the other side of the portal
if ( portal->GetNode(!side)->GetContents() & AREACONTENTS_SOLID ) {
return false;
}
if ( side ) {
normal = -(portal->GetPlane().Normal());
}
else {
normal = portal->GetPlane().Normal();
}
if ( normal * aasSettings->invGravityDir > aasSettings->minFloorCos ) {
return true;
}
return false;
}
/*
============
idAASBuild::GravSubdivLeafNode
============
*/
#define FACE_CHECKED BIT(31)
#define GRAVSUBDIV_EPSILON 0.1f
void idAASBuild::GravSubdivLeafNode( idBrushBSPNode *node ) {
int s1, s2, i, j, k, side1;
int numSplits, numSplitters;
idBrushBSPPortal *p1, *p2;
idWinding *w1, *w2;
idVec3 normal;
idPlane plane;
idPlaneSet planeList;
float d, min, max;
int *splitterOrder;
int *bestNumSplits;
int floor, gap, numFloorChecked;
// if this leaf node is already classified it cannot have a combination of floor and gap portals
if ( node->GetFlags() & (AREA_FLOOR|AREA_GAP) ) {
return;
}
floor = gap = 0;
// check if the area has a floor
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
if ( p1->GetFlags() & FACE_FLOOR ) {
floor++;
}
}
// find seperating planes between gap and floor portals
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
// if the portal is a gap seen from this side
if ( PortalIsGap( p1, s1 ) ) {
gap++;
// if the area doesn't have a floor
if ( !floor ) {
break;
}
}
else {
continue;
}
numFloorChecked = 0;
w1 = p1->GetWinding();
// test all edges of the gap
for ( i = 0; i < w1->GetNumPoints(); i++ ) {
// create a plane through the edge of the gap parallel to the direction of gravity
normal = (*w1)[(i+1)%w1->GetNumPoints()].ToVec3() - (*w1)[i].ToVec3();
normal = normal.Cross( aasSettings->invGravityDir );
if ( normal.Normalize() < 0.2f ) {
continue;
}
plane.SetNormal( normal );
plane.FitThroughPoint( (*w1)[i].ToVec3() );
// get the side of the plane the gap is on
side1 = w1->PlaneSide( plane, GRAVSUBDIV_EPSILON );
if ( side1 == SIDE_ON ) {
break;
}
// test if the plane through the edge of the gap seperates the gap from a floor portal
for ( p2 = node->GetPortals(); p2; p2 = p2->Next(s2) ) {
s2 = (p2->GetNode(1) == node);
if ( !( p2->GetFlags() & FACE_FLOOR ) ) {
continue;
}
if ( p2->GetFlags() & FACE_CHECKED ) {
continue;
}
w2 = p2->GetWinding();
min = 2.0f * GRAVSUBDIV_EPSILON;
max = GRAVSUBDIV_EPSILON;
if ( side1 == SIDE_FRONT ) {
for ( j = 0; j < w2->GetNumPoints(); j++ ) {
d = plane.Distance( (*w2)[j].ToVec3() );
if ( d >= GRAVSUBDIV_EPSILON ) {
break; // point at the same side of the plane as the gap
}
d = idMath::Fabs( d );
if ( d < min ) {
min = d;
}
if ( d > max ) {
max = d;
}
}
}
else {
for ( j = 0; j < w2->GetNumPoints(); j++ ) {
d = plane.Distance( (*w2)[j].ToVec3() );
if ( d <= -GRAVSUBDIV_EPSILON ) {
break; // point at the same side of the plane as the gap
}
d = idMath::Fabs( d );
if ( d < min ) {
min = d;
}
if ( d > max ) {
max = d;
}
}
}
// a point of the floor portal was found to be at the same side of the plane as the gap
if ( j < w2->GetNumPoints() ) {
continue;
}
// if the floor portal touches the plane
if ( min < GRAVSUBDIV_EPSILON && max > GRAVSUBDIV_EPSILON ) {
planeList.FindPlane( plane, 0.00001f, 0.1f );
}
p2->SetFlag( FACE_CHECKED );
numFloorChecked++;
}
if ( numFloorChecked == floor ) {
break;
}
}
for ( p2 = node->GetPortals(); p2; p2 = p2->Next(s2) ) {
s2 = (p2->GetNode(1) == node);
p2->RemoveFlag( FACE_CHECKED );
}
}
// if the leaf node does not have both floor and gap portals
if ( !( gap && floor) ) {
if ( floor ) {
node->SetFlag( AREA_FLOOR );
}
else if ( gap ) {
node->SetFlag( AREA_GAP );
}
return;
}
// if no valid seperators found
if ( planeList.Num() == 0 ) {
// NOTE: this should never happend, if it does the leaf node has degenerate portals
return;
}
splitterOrder = (int *) _alloca( planeList.Num() * sizeof( int ) );
bestNumSplits = (int *) _alloca( planeList.Num() * sizeof( int ) );
numSplitters = 0;
// test all possible seperators and sort them from best to worst
for ( i = 0; i < planeList.Num(); i += 2 ) {
numSplits = 0;
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
if ( p1->GetWinding()->PlaneSide( planeList[i], 0.1f ) == SIDE_CROSS ) {
numSplits++;
}
}
for ( j = 0; j < numSplitters; j++ ) {
if ( numSplits < bestNumSplits[j] ) {
for ( k = numSplitters; k > j; k-- ) {
bestNumSplits[k] = bestNumSplits[k-1];
splitterOrder[k] = splitterOrder[k-1];
}
bestNumSplits[j] = numSplits;
splitterOrder[j] = i;
numSplitters++;
break;
}
}
if ( j >= numSplitters ) {
bestNumSplits[j] = numSplits;
splitterOrder[j] = i;
numSplitters++;
}
}
// try all seperators in order from best to worst
for ( i = 0; i < numSplitters; i++ ) {
if ( node->Split( planeList[splitterOrder[i]], -1 ) ) {
// we found a seperator that works
break;
}
}
if ( i >= numSplitters) {
return;
}
DisplayRealTimeString( "\r%6d", ++numGravitationalSubdivisions );
// test children for further splits
GravSubdivLeafNode( node->GetChild(0) );
GravSubdivLeafNode( node->GetChild(1) );
}
/*
============
idAASBuild::GravSubdiv_r
============
*/
void idAASBuild::GravSubdiv_r( idBrushBSPNode *node ) {
if ( !node ) {
return;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
GravSubdivLeafNode( node );
return;
}
GravSubdiv_r( node->GetChild(0) );
GravSubdiv_r( node->GetChild(1) );
}
/*
============
idAASBuild::GravitationalSubdivision
============
*/
void idAASBuild::GravitationalSubdivision( idBrushBSP &bsp ) {
numGravitationalSubdivisions = 0;
common->Printf( "[Gravitational Subdivision]\n" );
SetPortalFlags_r( bsp.GetRootNode() );
GravSubdiv_r( bsp.GetRootNode() );
common->Printf( "\r%6d subdivisions\n", numGravitationalSubdivisions );
}
+575
View File
@@ -0,0 +1,575 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASBuild_local.h"
#define LEDGE_EPSILON 0.1f
//===============================================================
//
// idLedge
//
//===============================================================
/*
============
idLedge::idLedge
============
*/
idLedge::idLedge( void ) {
}
/*
============
idLedge::idLedge
============
*/
idLedge::idLedge( const idVec3 &v1, const idVec3 &v2, const idVec3 &gravityDir, idBrushBSPNode *n ) {
start = v1;
end = v2;
node = n;
numPlanes = 4;
planes[0].SetNormal( (v1 - v2).Cross( gravityDir ) );
planes[0].Normalize();
planes[0].FitThroughPoint( v1 );
planes[1].SetNormal( (v1 - v2).Cross( planes[0].Normal() ) );
planes[1].Normalize();
planes[1].FitThroughPoint( v1 );
planes[2].SetNormal( v1 - v2 );
planes[2].Normalize();
planes[2].FitThroughPoint( v1 );
planes[3].SetNormal( v2 - v1 );
planes[3].Normalize();
planes[3].FitThroughPoint( v2 );
}
/*
============
idLedge::AddPoint
============
*/
void idLedge::AddPoint( const idVec3 &v ) {
if ( planes[2].Distance( v ) > 0.0f ) {
start = v;
planes[2].FitThroughPoint( start );
}
if ( planes[3].Distance( v ) > 0.0f ) {
end = v;
planes[3].FitThroughPoint( end );
}
}
/*
============
idLedge::CreateBevels
NOTE: this assumes the gravity is vertical
============
*/
void idLedge::CreateBevels( const idVec3 &gravityDir ) {
int i, j;
idBounds bounds;
idVec3 size, normal;
bounds.Clear();
bounds.AddPoint( start );
bounds.AddPoint( end );
size = bounds[1] - bounds[0];
// plane through ledge
planes[0].SetNormal( (start - end).Cross( gravityDir ) );
planes[0].Normalize();
planes[0].FitThroughPoint( start );
// axial bevels at start and end point
i = size[1] > size[0];
normal = vec3_origin;
normal[i] = 1.0f;
j = end[i] > start[i];
planes[1+j].SetNormal( normal );
planes[1+!j].SetNormal( -normal );
planes[1].FitThroughPoint( start );
planes[2].FitThroughPoint( end );
numExpandedPlanes = 3;
// if additional bevels are required
if ( idMath::Fabs( size[!i] ) > 0.01f ) {
normal = vec3_origin;
normal[!i] = 1.0f;
j = end[!i] > start[!i];
planes[3+j].SetNormal( normal );
planes[3+!j].SetNormal( -normal );
planes[3].FitThroughPoint( start );
planes[4].FitThroughPoint( end );
numExpandedPlanes = 5;
}
// opposite of first
planes[numExpandedPlanes+0] = -planes[0];
// number of planes used for splitting
numSplitPlanes = numExpandedPlanes + 1;
// top plane
planes[numSplitPlanes+0].SetNormal( (start - end).Cross( planes[0].Normal() ) );
planes[numSplitPlanes+0].Normalize();
planes[numSplitPlanes+0].FitThroughPoint( start );
// bottom plane
planes[numSplitPlanes+1] = -planes[numSplitPlanes+0];
// total number of planes
numPlanes = numSplitPlanes + 2;
}
/*
============
idLedge::Expand
============
*/
void idLedge::Expand( const idBounds &bounds, float maxStepHeight ) {
int i, j;
idVec3 v;
for ( i = 0; i < numExpandedPlanes; i++ ) {
for ( j = 0; j < 3; j++ ) {
if ( planes[i].Normal()[j] > 0.0f ) {
v[j] = bounds[0][j];
}
else {
v[j] = bounds[1][j];
}
}
planes[i].SetDist( planes[i].Dist() + v * -planes[i].Normal() );
}
planes[numSplitPlanes+0].SetDist( planes[numSplitPlanes+0].Dist() + maxStepHeight );
planes[numSplitPlanes+1].SetDist( planes[numSplitPlanes+1].Dist() + 1.0f );
}
/*
============
idLedge::ChopWinding
============
*/
idWinding *idLedge::ChopWinding( const idWinding *winding ) const {
int i;
idWinding *w;
w = winding->Copy();
for ( i = 0; i < numPlanes && w; i++ ) {
w = w->Clip( -planes[i], ON_EPSILON, true );
}
return w;
}
/*
============
idLedge::PointBetweenBounds
============
*/
bool idLedge::PointBetweenBounds( const idVec3 &v ) const {
return ( planes[2].Distance( v ) < LEDGE_EPSILON ) && ( planes[3].Distance( v ) < LEDGE_EPSILON );
}
//===============================================================
//
// idAASBuild
//
//===============================================================
/*
============
idAASBuild::LedgeSubdivFlood_r
============
*/
void idAASBuild::LedgeSubdivFlood_r( idBrushBSPNode *node, const idLedge *ledge ) {
int s1, i;
idBrushBSPPortal *p1;
idWinding *w;
idList<idBrushBSPNode *> nodeList;
if ( node->GetFlags() & NODE_VISITED ) {
return;
}
// if this is not already a ledge area
if ( !( node->GetFlags() & AREA_LEDGE ) ) {
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
if ( !(p1->GetFlags() & FACE_FLOOR) ) {
continue;
}
// split the area if some part of the floor portal is inside the expanded ledge
w = ledge->ChopWinding( p1->GetWinding() );
if ( !w ) {
continue;
}
delete w;
for ( i = 0; i < ledge->numSplitPlanes; i++ ) {
if ( node->PlaneSide( ledge->planes[i], 0.1f ) != SIDE_CROSS ) {
continue;
}
if ( !node->Split( ledge->planes[i], -1 ) ) {
continue;
}
numLedgeSubdivisions++;
DisplayRealTimeString( "\r%6d", numLedgeSubdivisions );
node->GetChild(0)->SetFlag( NODE_VISITED );
LedgeSubdivFlood_r( node->GetChild(1), ledge );
return;
}
node->SetFlag( AREA_LEDGE );
break;
}
}
node->SetFlag( NODE_VISITED );
// get all nodes we might need to flood into
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
if ( p1->GetNode( !s1 )->GetContents() & AREACONTENTS_SOLID ) {
continue;
}
// flood through this portal if the portal is partly inside the expanded ledge
w = ledge->ChopWinding( p1->GetWinding() );
if ( !w ) {
continue;
}
delete w;
// add to list, cannot flood directly cause portals might be split on the way
nodeList.Append( p1->GetNode( !s1 ) );
}
// flood into other nodes
for ( i = 0; i < nodeList.Num(); i++ ) {
LedgeSubdivLeafNodes_r( nodeList[i], ledge );
}
}
/*
============
idAASBuild::LedgeSubdivLeafNodes_r
The node the ledge was originally part of might be split by other ledges.
Here we recurse down the tree from the original node to find all the new leaf nodes the ledge might be part of.
============
*/
void idAASBuild::LedgeSubdivLeafNodes_r( idBrushBSPNode *node, const idLedge *ledge ) {
if ( !node ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
LedgeSubdivFlood_r( node, ledge );
return;
}
LedgeSubdivLeafNodes_r( node->GetChild(0), ledge );
LedgeSubdivLeafNodes_r( node->GetChild(1), ledge );
}
/*
============
idAASBuild::LedgeSubdiv
============
*/
void idAASBuild::LedgeSubdiv( idBrushBSPNode *root ) {
int i, j;
idBrush *brush;
idList<idBrushSide *> sideList;
// create ledge bevels and expand ledges
for ( i = 0; i < ledgeList.Num(); i++ ) {
ledgeList[i].CreateBevels( aasSettings->gravityDir );
ledgeList[i].Expand( aasSettings->boundingBoxes[0], aasSettings->maxStepHeight );
// if we should write out a ledge map
if ( ledgeMap ) {
sideList.SetNum( 0 );
for ( j = 0; j < ledgeList[i].numPlanes; j++ ) {
sideList.Append( new idBrushSide( ledgeList[i].planes[j], -1 ) );
}
brush = new idBrush();
brush->FromSides( sideList );
ledgeMap->WriteBrush( brush );
delete brush;
}
// flood tree from the ledge node and subdivide areas with the ledge
LedgeSubdivLeafNodes_r( ledgeList[i].node, &ledgeList[i] );
// remove the node visited flags
ledgeList[i].node->RemoveFlagRecurseFlood( NODE_VISITED );
}
}
/*
============
idAASBuild::IsLedgeSide_r
============
*/
bool idAASBuild::IsLedgeSide_r( idBrushBSPNode *node, idFixedWinding *w, const idPlane &plane, const idVec3 &normal, const idVec3 &origin, const float radius ) {
int res, i;
idFixedWinding back;
float dist;
if ( !node ) {
return false;
}
while ( node->GetChild(0) && node->GetChild(1) ) {
dist = node->GetPlane().Distance( origin );
if ( dist > radius ) {
res = SIDE_FRONT;
}
else if ( dist < -radius ) {
res = SIDE_BACK;
}
else {
res = w->Split( &back, node->GetPlane(), LEDGE_EPSILON );
}
if ( res == SIDE_FRONT ) {
node = node->GetChild(0);
}
else if ( res == SIDE_BACK ) {
node = node->GetChild(1);
}
else if ( res == SIDE_ON ) {
// continue with the side the winding faces
if ( node->GetPlane().Normal() * normal > 0.0f ) {
node = node->GetChild(0);
}
else {
node = node->GetChild(1);
}
}
else {
if ( IsLedgeSide_r( node->GetChild(1), &back, plane, normal, origin, radius ) ) {
return true;
}
node = node->GetChild(0);
}
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return false;
}
for ( i = 0; i < w->GetNumPoints(); i++ ) {
if ( plane.Distance( (*w)[i].ToVec3() ) > 0.0f ) {
return true;
}
}
return false;
}
/*
============
idAASBuild::AddLedge
============
*/
void idAASBuild::AddLedge( const idVec3 &v1, const idVec3 &v2, idBrushBSPNode *node ) {
int i, j, merged;
// first try to merge the ledge with existing ledges
merged = -1;
for ( i = 0; i < ledgeList.Num(); i++ ) {
for ( j = 0; j < 2; j++ ) {
if ( idMath::Fabs( ledgeList[i].planes[j].Distance( v1 ) ) > LEDGE_EPSILON ) {
break;
}
if ( idMath::Fabs( ledgeList[i].planes[j].Distance( v2 ) ) > LEDGE_EPSILON ) {
break;
}
}
if ( j < 2 ) {
continue;
}
if ( !ledgeList[i].PointBetweenBounds( v1 ) &&
!ledgeList[i].PointBetweenBounds( v2 ) ) {
continue;
}
if ( merged == -1 ) {
ledgeList[i].AddPoint( v1 );
ledgeList[i].AddPoint( v2 );
merged = i;
}
else {
ledgeList[merged].AddPoint( ledgeList[i].start );
ledgeList[merged].AddPoint( ledgeList[i].end );
ledgeList.RemoveIndex(i);
break;
}
}
// if the ledge could not be merged
if ( merged == -1 ) {
ledgeList.Append( idLedge( v1, v2, aasSettings->gravityDir, node ) );
}
}
/*
============
idAASBuild::FindLeafNodeLedges
============
*/
void idAASBuild::FindLeafNodeLedges( idBrushBSPNode *root, idBrushBSPNode *node ) {
int s1, i;
idBrushBSPPortal *p1;
idWinding *w;
idVec3 v1, v2, normal, origin;
idFixedWinding winding;
idBounds bounds;
idPlane plane;
float radius;
for ( p1 = node->GetPortals(); p1; p1 = p1->Next(s1) ) {
s1 = (p1->GetNode(1) == node);
if ( !(p1->GetFlags() & FACE_FLOOR) ) {
continue;
}
if ( s1 ) {
plane = p1->GetPlane();
w = p1->GetWinding()->Reverse();
}
else {
plane = -p1->GetPlane();
w = p1->GetWinding();
}
for ( i = 0; i < w->GetNumPoints(); i++ ) {
v1 = (*w)[i].ToVec3();
v2 = (*w)[(i+1)%w->GetNumPoints()].ToVec3();
normal = (v2 - v1).Cross( aasSettings->gravityDir );
if ( normal.Normalize() < 0.5f ) {
continue;
}
winding.Clear();
winding += v1 + normal * LEDGE_EPSILON * 0.5f;
winding += v2 + normal * LEDGE_EPSILON * 0.5f;
winding += winding[1].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
winding += winding[0].ToVec3() + ( aasSettings->maxStepHeight + 1.0f ) * aasSettings->gravityDir;
winding.GetBounds( bounds );
origin = (bounds[1] - bounds[0]) * 0.5f;
radius = origin.Length() + LEDGE_EPSILON;
origin = bounds[0] + origin;
plane.FitThroughPoint( v1 + aasSettings->maxStepHeight * aasSettings->gravityDir );
if ( !IsLedgeSide_r( root, &winding, plane, normal, origin, radius ) ) {
continue;
}
AddLedge( v1, v2, node );
}
if ( w != p1->GetWinding() ) {
delete w;
}
}
}
/*
============
idAASBuild::FindLedges_r
============
*/
void idAASBuild::FindLedges_r( idBrushBSPNode *root, idBrushBSPNode *node ) {
if ( !node ) {
return;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
if ( node->GetFlags() & NODE_VISITED ) {
return;
}
FindLeafNodeLedges( root, node );
node->SetFlag( NODE_VISITED );
return;
}
FindLedges_r( root, node->GetChild(0) );
FindLedges_r( root, node->GetChild(1) );
}
/*
============
idAASBuild::WriteLedgeMap
============
*/
void idAASBuild::WriteLedgeMap( const idStr &fileName, const idStr &ext ) {
ledgeMap = new idBrushMap( fileName, ext );
ledgeMap->SetTexture( "textures/base_trim/bluetex4q_ed" );
}
/*
============
idAASBuild::LedgeSubdivision
NOTE: this assumes the bounding box is higher than the maximum step height
only ledges with vertical sides are considered
============
*/
void idAASBuild::LedgeSubdivision( idBrushBSP &bsp ) {
numLedgeSubdivisions = 0;
ledgeList.Clear();
common->Printf( "[Ledge Subdivision]\n" );
bsp.GetRootNode()->RemoveFlagRecurse( NODE_VISITED );
FindLedges_r( bsp.GetRootNode(), bsp.GetRootNode() );
bsp.GetRootNode()->RemoveFlagRecurse( NODE_VISITED );
common->Printf( "\r%6d ledges\n", ledgeList.Num() );
LedgeSubdiv( bsp.GetRootNode() );
common->Printf( "\r%6d subdivisions\n", numLedgeSubdivisions );
}
+163
View File
@@ -0,0 +1,163 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASBuild_local.h"
/*
============
idAASBuild::AllGapsLeadToOtherNode
============
*/
bool idAASBuild::AllGapsLeadToOtherNode( idBrushBSPNode *nodeWithGaps, idBrushBSPNode *otherNode ) {
int s;
idBrushBSPPortal *p;
for ( p = nodeWithGaps->GetPortals(); p; p = p->Next(s) ) {
s = (p->GetNode(1) == nodeWithGaps);
if ( !PortalIsGap( p, s ) ) {
continue;
}
if ( p->GetNode(!s) != otherNode ) {
return false;
}
}
return true;
}
/*
============
idAASBuild::MergeWithAdjacentLeafNodes
============
*/
bool idAASBuild::MergeWithAdjacentLeafNodes( idBrushBSP &bsp, idBrushBSPNode *node ) {
int s, numMerges = 0, otherNodeFlags;
idBrushBSPPortal *p;
do {
for ( p = node->GetPortals(); p; p = p->Next(s) ) {
s = (p->GetNode(1) == node);
// both leaf nodes must have the same contents
if ( node->GetContents() != p->GetNode(!s)->GetContents() ) {
continue;
}
// cannot merge leaf nodes if one is near a ledge and the other is not
if ( (node->GetFlags() & AREA_LEDGE) != (p->GetNode(!s)->GetFlags() & AREA_LEDGE) ) {
continue;
}
// cannot merge leaf nodes if one has a floor portal and the other a gap portal
if ( node->GetFlags() & AREA_FLOOR ) {
if ( p->GetNode(!s)->GetFlags() & AREA_GAP ) {
if ( !AllGapsLeadToOtherNode( p->GetNode(!s), node ) ) {
continue;
}
}
}
else if ( node->GetFlags() & AREA_GAP ) {
if ( p->GetNode(!s)->GetFlags() & AREA_FLOOR ) {
if ( !AllGapsLeadToOtherNode( node, p->GetNode(!s) ) ) {
continue;
}
}
}
otherNodeFlags = p->GetNode(!s)->GetFlags();
// try to merge the leaf nodes
if ( bsp.TryMergeLeafNodes( p, s ) ) {
node->SetFlag( otherNodeFlags );
if ( node->GetFlags() & AREA_FLOOR ) {
node->RemoveFlag( AREA_GAP );
}
numMerges++;
DisplayRealTimeString( "\r%6d", ++numMergedLeafNodes );
break;
}
}
} while( p );
if ( numMerges ) {
return true;
}
return false;
}
/*
============
idAASBuild::MergeLeafNodes_r
============
*/
void idAASBuild::MergeLeafNodes_r( idBrushBSP &bsp, idBrushBSPNode *node ) {
if ( !node ) {
return;
}
if ( node->GetContents() & AREACONTENTS_SOLID ) {
return;
}
if ( node->GetFlags() & NODE_DONE ) {
return;
}
if ( !node->GetChild(0) && !node->GetChild(1) ) {
MergeWithAdjacentLeafNodes( bsp, node );
node->SetFlag( NODE_DONE );
return;
}
MergeLeafNodes_r( bsp, node->GetChild(0) );
MergeLeafNodes_r( bsp, node->GetChild(1) );
return;
}
/*
============
idAASBuild::MergeLeafNodes
============
*/
void idAASBuild::MergeLeafNodes( idBrushBSP &bsp ) {
numMergedLeafNodes = 0;
common->Printf( "[Merge Leaf Nodes]\n" );
MergeLeafNodes_r( bsp, bsp.GetRootNode() );
bsp.GetRootNode()->RemoveFlagRecurse( NODE_DONE );
bsp.PruneMergedTree_r( bsp.GetRootNode() );
common->Printf( "\r%6d leaf nodes merged\n", numMergedLeafNodes );
}
+556
View File
@@ -0,0 +1,556 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASFile.h"
#include "AASFile_local.h"
#include "AASCluster.h"
/*
================
idAASCluster::UpdatePortal
================
*/
bool idAASCluster::UpdatePortal( int areaNum, int clusterNum ) {
int portalNum;
aasPortal_t *portal;
// find the portal for this area
for ( portalNum = 1; portalNum < file->portals.Num(); portalNum++ ) {
if ( file->portals[portalNum].areaNum == areaNum ) {
break;
}
}
if ( portalNum >= file->portals.Num() ) {
common->Error( "no portal for area %d", areaNum );
return true;
}
portal = &file->portals[portalNum];
// if the portal is already fully updated
if ( portal->clusters[0] == clusterNum ) {
return true;
}
if ( portal->clusters[1] == clusterNum ) {
return true;
}
// if the portal has no front cluster yet
if ( !portal->clusters[0] ) {
portal->clusters[0] = clusterNum;
}
// if the portal has no back cluster yet
else if ( !portal->clusters[1] )
{
portal->clusters[1] = clusterNum;
}
else
{
// remove the cluster portal flag contents
file->areas[areaNum].contents &= ~AREACONTENTS_CLUSTERPORTAL;
return false;
}
// set the area cluster number to the negative portal number
file->areas[areaNum].cluster = -portalNum;
// add the portal to the cluster using the portal index
file->AppendPortalIndex( portalNum, clusterNum );
return true;
}
/*
================
idAASCluster::FloodClusterAreas_r
================
*/
bool idAASCluster::FloodClusterAreas_r( int areaNum, int clusterNum ) {
aasArea_t *area;
aasFace_t *face;
int faceNum, i;
idReachability *reach;
area = &file->areas[areaNum];
// if the area is already part of a cluster
if ( area->cluster > 0 ) {
if ( area->cluster == clusterNum ) {
return true;
}
// there's a reachability going from one cluster to another only in one direction
common->Error( "cluster %d touched cluster %d at area %d\r\n", clusterNum, file->areas[areaNum].cluster, areaNum );
return false;
}
// if this area is a cluster portal
if ( area->contents & AREACONTENTS_CLUSTERPORTAL ) {
return UpdatePortal( areaNum, clusterNum );
}
// set the area cluster number
area->cluster = clusterNum;
if ( !noFaceFlood ) {
// use area faces to flood into adjacent areas
for ( i = 0; i < area->numFaces; i++ ) {
faceNum = abs(file->faceIndex[area->firstFace + i]);
face = &file->faces[faceNum];
if ( face->areas[0] == areaNum ) {
if ( face->areas[1] ) {
if ( !FloodClusterAreas_r( face->areas[1], clusterNum ) ) {
return false;
}
}
}
else {
if ( face->areas[0] ) {
if ( !FloodClusterAreas_r( face->areas[0], clusterNum ) ) {
return false;
}
}
}
}
}
// use the reachabilities to flood into other areas
for ( reach = file->areas[areaNum].reach; reach; reach = reach->next ) {
if ( !FloodClusterAreas_r( reach->toAreaNum, clusterNum) ) {
return false;
}
}
// use the reversed reachabilities to flood into other areas
for ( reach = file->areas[areaNum].rev_reach; reach; reach = reach->rev_next ) {
if ( !FloodClusterAreas_r( reach->fromAreaNum, clusterNum) ) {
return false;
}
}
return true;
}
/*
================
idAASCluster::RemoveAreaClusterNumbers
================
*/
void idAASCluster::RemoveAreaClusterNumbers( void ) {
int i;
for ( i = 1; i < file->areas.Num(); i++ ) {
file->areas[i].cluster = 0;
}
}
/*
================
idAASCluster::NumberClusterAreas
================
*/
void idAASCluster::NumberClusterAreas( int clusterNum ) {
int i, portalNum;
aasCluster_t *cluster;
aasPortal_t *portal;
cluster = &file->clusters[clusterNum];
cluster->numAreas = 0;
cluster->numReachableAreas = 0;
// number all areas in this cluster WITH reachabilities
for ( i = 1; i < file->areas.Num(); i++ ) {
if ( file->areas[i].cluster != clusterNum ) {
continue;
}
if ( !(file->areas[i].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) ) {
continue;
}
file->areas[i].clusterAreaNum = cluster->numAreas++;
cluster->numReachableAreas++;
}
// number all portals in this cluster WITH reachabilities
for ( i = 0; i < cluster->numPortals; i++ ) {
portalNum = file->portalIndex[cluster->firstPortal + i];
portal = &file->portals[portalNum];
if ( !(file->areas[portal->areaNum].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) ) {
continue;
}
if ( portal->clusters[0] == clusterNum ) {
portal->clusterAreaNum[0] = cluster->numAreas++;
}
else {
portal->clusterAreaNum[1] = cluster->numAreas++;
}
cluster->numReachableAreas++;
}
// number all areas in this cluster WITHOUT reachabilities
for ( i = 1; i < file->areas.Num(); i++ ) {
if ( file->areas[i].cluster != clusterNum ) {
continue;
}
if ( file->areas[i].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) {
continue;
}
file->areas[i].clusterAreaNum = cluster->numAreas++;
}
// number all portals in this cluster WITHOUT reachabilities
for ( i = 0; i < cluster->numPortals; i++ ) {
portalNum = file->portalIndex[cluster->firstPortal + i];
portal = &file->portals[portalNum];
if ( file->areas[portal->areaNum].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) {
continue;
}
if ( portal->clusters[0] == clusterNum ) {
portal->clusterAreaNum[0] = cluster->numAreas++;
}
else {
portal->clusterAreaNum[1] = cluster->numAreas++;
}
}
}
/*
================
idAASCluster::FindClusters
================
*/
bool idAASCluster::FindClusters( void ) {
int i, clusterNum;
aasCluster_t cluster;
RemoveAreaClusterNumbers();
for ( i = 1; i < file->areas.Num(); i++ ) {
// if the area is already part of a cluster
if ( file->areas[i].cluster ) {
continue;
}
// if not flooding through faces only use areas that have reachabilities
if ( noFaceFlood ) {
if ( !(file->areas[i].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY)) ) {
continue;
}
}
// if the area is a cluster portal
if ( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL ) {
continue;
}
cluster.numAreas = 0;
cluster.numReachableAreas = 0;
cluster.firstPortal = file->portalIndex.Num();
cluster.numPortals = 0;
clusterNum = file->clusters.Num();
file->clusters.Append( cluster );
// flood the areas in this cluster
if ( !FloodClusterAreas_r( i, clusterNum ) ) {
return false;
}
// number the cluster areas
NumberClusterAreas( clusterNum );
}
return true;
}
/*
================
idAASCluster::CreatePortals
================
*/
void idAASCluster::CreatePortals( void ) {
int i;
aasPortal_t portal;
for ( i = 1; i < file->areas.Num(); i++ ) {
// if the area is a cluster portal
if ( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL ) {
portal.areaNum = i;
portal.clusters[0] = portal.clusters[1] = 0;
portal.maxAreaTravelTime = 0;
file->portals.Append( portal );
}
}
}
/*
================
idAASCluster::TestPortals
================
*/
bool idAASCluster::TestPortals( void ) {
int i;
aasPortal_t *portal, *portal2;
aasArea_t *area, *area2;
idReachability *reach;
bool ok;
ok = true;
for ( i = 1; i < file->portals.Num(); i++ ) {
portal = &file->portals[i];
area = &file->areas[portal->areaNum];
// if this portal was already removed
if ( !( area->contents & AREACONTENTS_CLUSTERPORTAL) ) {
continue;
}
// may not removed this portal if it has a reachability to a removed portal
for ( reach = area->reach; reach; reach = reach->next ) {
area2 = &file->areas[ reach->toAreaNum ];
if ( area2->contents & AREACONTENTS_CLUSTERPORTAL ) {
continue;
}
if ( area2->cluster < 0 ) {
break;
}
}
if ( reach ) {
continue;
}
// may not removed this portal if it has a reversed reachability to a removed portal
for ( reach = area->rev_reach; reach; reach = reach->rev_next ) {
area2 = &file->areas[ reach->toAreaNum ];
if ( area2->contents & AREACONTENTS_CLUSTERPORTAL ) {
continue;
}
if ( area2->cluster < 0 ) {
break;
}
}
if ( reach ) {
continue;
}
// portal should have two clusters set
if ( !portal->clusters[0] ) {
area->contents &= ~AREACONTENTS_CLUSTERPORTAL;
ok = false;
continue;
}
if ( !portal->clusters[1] ) {
area->contents &= ~AREACONTENTS_CLUSTERPORTAL;
ok = false;
continue;
}
// this portal may not have reachabilities to a portal that doesn't seperate the same clusters
for ( reach = area->reach; reach; reach = reach->next ) {
area2 = &file->areas[ reach->toAreaNum ];
if ( !(area2->contents & AREACONTENTS_CLUSTERPORTAL) ) {
continue;
}
if ( area2->cluster > 0 ) {
area2->contents &= ~AREACONTENTS_CLUSTERPORTAL;
ok = false;
continue;
}
portal2 = &file->portals[ -file->areas[ reach->toAreaNum ].cluster ];
if ( ( portal2->clusters[0] != portal->clusters[0] && portal2->clusters[0] != portal->clusters[1] ) ||
( portal2->clusters[1] != portal->clusters[0] && portal2->clusters[1] != portal->clusters[1] ) ) {
area2->contents &= ~AREACONTENTS_CLUSTERPORTAL;
ok = false;
continue;
}
}
}
return ok;
}
/*
================
idAASCluster::RemoveInvalidPortals
================
*/
void idAASCluster::RemoveInvalidPortals( void ) {
int i, j, k, face1Num, face2Num, otherAreaNum, numOpenAreas, numInvalidPortals;
aasFace_t *face1, *face2;
numInvalidPortals = 0;
for ( i = 0; i < file->areas.Num(); i++ ) {
if ( !( file->areas[i].contents & AREACONTENTS_CLUSTERPORTAL ) ) {
continue;
}
numOpenAreas = 0;
for ( j = 0; j < file->areas[i].numFaces; j++ ) {
face1Num = file->faceIndex[ file->areas[i].firstFace + j ];
face1 = &file->faces[ abs(face1Num) ];
otherAreaNum = face1->areas[ face1Num < 0 ];
if ( !otherAreaNum ) {
continue;
}
for ( k = 0; k < j; k++ ) {
face2Num = file->faceIndex[ file->areas[i].firstFace + k ];
face2 = &file->faces[ abs(face2Num) ];
if ( otherAreaNum == face2->areas[ face2Num < 0 ] ) {
break;
}
}
if ( k < j ) {
continue;
}
if ( !( file->areas[otherAreaNum].contents & AREACONTENTS_CLUSTERPORTAL ) ) {
numOpenAreas++;
}
}
if ( numOpenAreas <= 1 ) {
file->areas[i].contents &= AREACONTENTS_CLUSTERPORTAL;
numInvalidPortals++;
}
}
common->Printf( "\r%6d invalid portals removed\n", numInvalidPortals );
}
/*
================
idAASCluster::Build
================
*/
bool idAASCluster::Build( idAASCompilerFile *file ) {
common->Printf( "[Clustering]\n" );
this->file = file;
this->noFaceFlood = true;
RemoveInvalidPortals();
while( 1 ) {
// delete all existing clusters
file->DeleteClusters();
// create the portals from the portal areas
CreatePortals();
common->Printf( "\r%6d", file->portals.Num() );
// find the clusters
if ( !FindClusters() ) {
continue;
}
// test the portals
if ( !TestPortals() ) {
continue;
}
break;
}
common->Printf( "\r%6d portals\n", file->portals.Num() );
common->Printf( "%6d clusters\n", file->clusters.Num() );
for ( int i = 0; i < file->clusters.Num(); i++ ) {
common->Printf( "%6d reachable areas in cluster %d\n", file->clusters[i].numReachableAreas, i );
}
file->ReportRoutingEfficiency();
return true;
}
/*
================
idAASCluster::BuildSingleCluster
================
*/
bool idAASCluster::BuildSingleCluster( idAASCompilerFile *file ) {
int i, numAreas;
aasCluster_t cluster;
common->Printf( "[Clustering]\n" );
this->file = file;
// delete all existing clusters
file->DeleteClusters();
cluster.firstPortal = 0;
cluster.numPortals = 0;
cluster.numAreas = file->areas.Num();
cluster.numReachableAreas = 0;
// give all reachable areas in the cluster a number
for ( i = 0; i < file->areas.Num(); i++ ) {
file->areas[i].cluster = file->clusters.Num();
if ( file->areas[i].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) {
file->areas[i].clusterAreaNum = cluster.numReachableAreas++;
}
}
// give the remaining areas a number within the cluster
numAreas = cluster.numReachableAreas;
for ( i = 0; i < file->areas.Num(); i++ ) {
if ( file->areas[i].flags & (AREA_REACHABLE_WALK|AREA_REACHABLE_FLY) ) {
continue;
}
file->areas[i].clusterAreaNum = numAreas++;
}
file->clusters.Append( cluster );
common->Printf( "%6d portals\n", file->portals.Num() );
common->Printf( "%6d clusters\n", file->clusters.Num() );
for ( i = 0; i < file->clusters.Num(); i++ ) {
common->Printf( "%6d reachable areas in cluster %d\n", file->clusters[i].numReachableAreas, i );
}
file->ReportRoutingEfficiency();
return true;
}
+147
View File
@@ -0,0 +1,147 @@
/*
===========================================================================
Quake 4 Reconstructed GPL Source Code
Copyright (C) 2026 Justin Marshall(IceColdDuke).
===========================================================================
*/
#ifndef __AASCOMPILERFILE_H__
#define __AASCOMPILERFILE_H__
#include "AASFile.h"
/*
===============================================================================
Compiler-facing adapter for the Quake 4 idAASFile interface.
The Doom 3 compiler operated directly on idAASFileLocal's idList members.
Quake 4 deliberately exposes the same operations through idAASFile virtuals
so the compiler in Toolsx86.dll does not depend on the engine's private AAS
object layout. These small list views preserve the original compiler code's
shape while routing every access through that public interface.
===============================================================================
*/
template< class type >
class idAASCompilerList {
public:
typedef int ( idAASFile::*numFunction_t )( void ) const;
typedef type &( idAASFile::*getFunction_t )( int );
typedef int ( idAASFile::*appendFunction_t )( type & );
typedef void ( idAASFile::*setNumFunction_t )( int );
idAASCompilerList( idAASFile *file, numFunction_t numFunction,
getFunction_t getFunction, appendFunction_t appendFunction = NULL,
setNumFunction_t setNumFunction = NULL ) :
file( file ), numFunction( numFunction ), getFunction( getFunction ),
appendFunction( appendFunction ), setNumFunction( setNumFunction ) {
}
int Num( void ) const {
return ( file->*numFunction )();
}
type &operator[]( int index ) {
return ( file->*getFunction )( index );
}
int Append( type &value ) {
assert( appendFunction != NULL );
return ( file->*appendFunction )( value );
}
void SetNum( int count ) {
assert( setNumFunction != NULL );
( file->*setNumFunction )( count );
}
private:
idAASFile * file;
numFunction_t numFunction;
getFunction_t getFunction;
appendFunction_t appendFunction;
setNumFunction_t setNumFunction;
};
class idAASCompilerPlaneList {
public:
explicit idAASCompilerPlaneList( idAASFile *file ) : file( file ) {}
idPlane &operator[]( int index ) {
return file->GetPlane( index );
}
int FindPlane( const idPlane &plane, float normalEpsilon, float distanceEpsilon ) {
return file->FindPlane( plane, normalEpsilon, distanceEpsilon );
}
private:
idAASFile *file;
};
class idAASCompilerFile {
public:
explicit idAASCompilerFile( idAASFile *file ) :
file( file ),
planeList( file ),
vertices( file, &idAASFile::GetNumVertices, &idAASFile::GetVertex, &idAASFile::AppendVertex ),
edges( file, &idAASFile::GetNumEdges, &idAASFile::GetEdge, &idAASFile::AppendEdge ),
edgeIndex( file, &idAASFile::GetNumEdgeIndexes, &idAASFile::GetEdgeIndex, &idAASFile::AppendEdgeIndex ),
faces( file, &idAASFile::GetNumFaces, &idAASFile::GetFace, &idAASFile::AppendFace ),
faceIndex( file, &idAASFile::GetNumFaceIndexes, &idAASFile::GetFaceIndex, &idAASFile::AppendFaceIndex ),
areas( file, &idAASFile::GetNumAreas, &idAASFile::GetArea, &idAASFile::AppendArea ),
nodes( file, &idAASFile::GetNumNodes, &idAASFile::GetNode, &idAASFile::AppendNode, &idAASFile::SetNumNodes ),
portals( file, &idAASFile::GetNumPortals, &idAASFile::GetPortal, &idAASFile::AppendPortal ),
portalIndex( file, &idAASFile::GetNumPortalIndexes, &idAASFile::GetPortalIndex ),
clusters( file, &idAASFile::GetNumClusters, &idAASFile::GetCluster, &idAASFile::AppendCluster ),
settings( file->GetSettings() ) {
assert( file != NULL );
}
~idAASCompilerFile( void ) {
delete file;
}
void Clear( void ) { file->Clear(); }
void DeleteClusters( void ) { file->DeleteClusters(); }
void DeleteReachabilities( void ) { file->DeleteReachabilities(); }
idVec3 EdgeCenter( int edgeNum ) const { return file->EdgeCenter( edgeNum ); }
idVec3 FaceCenter( int faceNum ) const { return file->FaceCenter( faceNum ); }
void FinishAreas( void ) { file->FinishAreas(); }
idAASSettings &GetSettings( void ) { return file->GetSettings(); }
void LinkReversedReachability( void ) { file->LinkReversedReachability(); }
bool Load( const idStr &name, unsigned int crc ) { return file->Load( name, crc ); }
void Optimize( void ) { file->Optimize(); }
void ReportRoutingEfficiency( void ) const { file->ReportRoutingEfficiency(); }
void SetSizes( sizeEstimate_t size ) { file->SetSizes( size ); }
bool Trace( aasTrace_t &trace, const idVec3 &start, const idVec3 &end ) const { return file->Trace( trace, start, end ); }
bool Write( const idStr &name, unsigned int crc ) { return file->Write( name, crc ); }
int AppendPortalIndex( aasIndex_t &portalNum, int clusterNum ) {
return file->AppendPortalIndex( portalNum, clusterNum );
}
idAASFile *GetFile( void ) { return file; }
idAASCompilerPlaneList planeList;
idAASCompilerList< aasVertex_t > vertices;
idAASCompilerList< aasEdge_t > edges;
idAASCompilerList< aasIndex_t > edgeIndex;
idAASCompilerList< aasFace_t > faces;
idAASCompilerList< aasIndex_t > faceIndex;
idAASCompilerList< aasArea_t > areas;
idAASCompilerList< aasNode_t > nodes;
idAASCompilerList< aasPortal_t > portals;
idAASCompilerList< aasIndex_t > portalIndex;
idAASCompilerList< aasCluster_t > clusters;
idAASSettings & settings;
private:
idAASFile *file;
};
#endif /* !__AASCOMPILERFILE_H__ */
+945
View File
@@ -0,0 +1,945 @@
/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
Doom 3 Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASFile.h"
#include "AASFile_local.h"
#include "AASReach.h"
#define INSIDEUNITS 2.0f
#define INSIDEUNITS_WALKEND 0.5f
#define INSIDEUNITS_WALKSTART 0.1f
#define INSIDEUNITS_SWIMEND 0.5f
#define INSIDEUNITS_FLYEND 0.5f
#define INSIDEUNITS_WATERJUMP 15.0f
/*
================
idAASReach::ReachabilityExists
================
*/
bool idAASReach::ReachabilityExists( int fromAreaNum, int toAreaNum ) {
aasArea_t *area;
idReachability *reach;
area = &file->areas[fromAreaNum];
for ( reach = area->reach; reach; reach = reach->next ) {
if ( reach->toAreaNum == toAreaNum ) {
return true;
}
}
return false;
}
/*
================
idAASReach::CanSwimInArea
================
*/
ID_INLINE bool idAASReach::CanSwimInArea( int areaNum ) {
return ( file->areas[areaNum].contents & AREACONTENTS_WATER ) != 0;
}
/*
================
idAASReach::AreaHasFloor
================
*/
ID_INLINE bool idAASReach::AreaHasFloor( int areaNum ) {
return ( file->areas[areaNum].flags & AREA_FLOOR ) != 0;
}
/*
================
idAASReach::AreaIsClusterPortal
================
*/
ID_INLINE bool idAASReach::AreaIsClusterPortal( int areaNum ) {
return ( file->areas[areaNum].contents & AREACONTENTS_CLUSTERPORTAL ) != 0;
}
/*
================
idAASReach::AddReachabilityToArea
================
*/
void idAASReach::AddReachabilityToArea( idReachability *reach, int areaNum ) {
aasArea_t *area;
area = &file->areas[areaNum];
reach->next = area->reach;
area->reach = reach;
numReachabilities++;
}
/*
================
idAASReach::Reachability_Fly
================
*/
void idAASReach::Reachability_Fly( int areaNum ) {
int i, faceNum, otherAreaNum;
aasArea_t *area;
aasFace_t *face;
idReachability_Fly *reach;
area = &file->areas[areaNum];
for ( i = 0; i < area->numFaces; i++ ) {
faceNum = file->faceIndex[area->firstFace + i];
face = &file->faces[abs(faceNum)];
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
if ( otherAreaNum == 0 ) {
continue;
}
if ( ReachabilityExists( areaNum, otherAreaNum ) ) {
continue;
}
// create reachability going through this face
reach = new idReachability_Fly();
reach->travelType = TFL_FLY;
reach->toAreaNum = otherAreaNum;
reach->fromAreaNum = areaNum;
reach->edgeNum = 0;
reach->travelTime = 1;
reach->start = file->FaceCenter( abs(faceNum) );
if ( faceNum < 0 ) {
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_FLYEND;
} else {
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_FLYEND;
}
AddReachabilityToArea( reach, areaNum );
}
}
/*
================
idAASReach::Reachability_Swim
================
*/
void idAASReach::Reachability_Swim( int areaNum ) {
int i, faceNum, otherAreaNum;
aasArea_t *area;
aasFace_t *face;
idReachability_Swim *reach;
if ( !CanSwimInArea( areaNum ) ) {
return;
}
area = &file->areas[areaNum];
for ( i = 0; i < area->numFaces; i++ ) {
faceNum = file->faceIndex[area->firstFace + i];
face = &file->faces[abs(faceNum)];
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
if ( otherAreaNum == 0 ) {
continue;
}
if ( !CanSwimInArea( otherAreaNum ) ) {
continue;
}
if ( ReachabilityExists( areaNum, otherAreaNum ) ) {
continue;
}
// create reachability going through this face
reach = new idReachability_Swim();
reach->travelType = TFL_SWIM;
reach->toAreaNum = otherAreaNum;
reach->fromAreaNum = areaNum;
reach->edgeNum = 0;
reach->travelTime = 1;
reach->start = file->FaceCenter( abs(faceNum) );
if ( faceNum < 0 ) {
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_SWIMEND;
} else {
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_SWIMEND;
}
AddReachabilityToArea( reach, areaNum );
}
}
/*
================
idAASReach::Reachability_EqualFloorHeight
================
*/
void idAASReach::Reachability_EqualFloorHeight( int areaNum ) {
int i, k, l, m, n, faceNum, face1Num, face2Num, otherAreaNum, edge1Num, edge2Num;
aasArea_t *area, *otherArea;
aasFace_t *face, *face1, *face2;
idReachability_Walk *reach;
if ( !AreaHasFloor( areaNum ) ) {
return;
}
area = &file->areas[areaNum];
for ( i = 0; i < area->numFaces; i++ ) {
faceNum = file->faceIndex[area->firstFace + i];
face = &file->faces[abs(faceNum)];
otherAreaNum = face->areas[INTSIGNBITNOTSET(faceNum)];
if ( !AreaHasFloor( otherAreaNum ) ) {
continue;
}
otherArea = &file->areas[otherAreaNum];
for ( k = 0; k < area->numFaces; k++ ) {
face1Num = file->faceIndex[area->firstFace + k];
face1 = &file->faces[abs(face1Num)];
if ( !( face1->flags & FACE_FLOOR ) ) {
continue;
}
for ( l = 0; l < otherArea->numFaces; l++ ) {
face2Num = file->faceIndex[otherArea->firstFace + l];
face2 = &file->faces[abs(face2Num)];
if ( !( face2->flags & FACE_FLOOR ) ) {
continue;
}
for ( m = 0; m < face1->numEdges; m++ ) {
edge1Num = abs(file->edgeIndex[face1->firstEdge + m]);
for ( n = 0; n < face2->numEdges; n++ ) {
edge2Num = abs(file->edgeIndex[face2->firstEdge + n]);
if ( edge1Num == edge2Num ) {
break;
}
}
if ( n < face2->numEdges ) {
break;
}
}
if ( m < face1->numEdges ) {
break;
}
}
if ( l < otherArea->numFaces ) {
break;
}
}
if ( k < area->numFaces ) {
// create reachability
reach = new idReachability_Walk();
reach->travelType = TFL_WALK;
reach->toAreaNum = otherAreaNum;
reach->fromAreaNum = areaNum;
reach->edgeNum = abs( edge1Num );
reach->travelTime = 1;
reach->start = file->EdgeCenter( edge1Num );
if ( faceNum < 0 ) {
reach->end = reach->start + file->planeList[face->planeNum].Normal() * INSIDEUNITS_WALKEND;
}
else {
reach->end = reach->start - file->planeList[face->planeNum].Normal() * INSIDEUNITS_WALKEND;
}
AddReachabilityToArea( reach, areaNum );
}
}
}
/*
================
idAASReach::Reachability_Step_Barrier_WaterJump_WalkOffLedge
================
*/
bool idAASReach::Reachability_Step_Barrier_WaterJump_WalkOffLedge( int area1num, int area2num ) {
int i, j, k, l, edge1Num, edge2Num, areas[10];
int floor_bestArea1FloorEdgeNum, floor_bestArea2FloorEdgeNum, floor_foundReach;
int water_bestArea1FloorEdgeNum, water_bestArea2FloorEdgeNum, water_foundReach;
int side1, faceSide1, floorFace1Num;
float dist, dist1, dist2, diff, invGravityDot, orthogonalDot;
float x1, x2, x3, x4, y1, y2, y3, y4, tmp, y;
float length, floor_bestLength, water_bestLength, floor_bestDist, water_bestDist;
idVec3 v1, v2, v3, v4, tmpv, p1area1, p1area2, p2area1, p2area2;
idVec3 normal, orthogonal, edgeVec, start, end;
idVec3 floor_bestStart, floor_bestEnd, floor_bestNormal;
idVec3 water_bestStart, water_bestEnd, water_bestNormal;
idVec3 testPoint;
idPlane *plane;
aasArea_t *area1, *area2;
aasFace_t *floorFace1, *floorFace2, *floor_bestFace1, *water_bestFace1;
aasEdge_t *edge1, *edge2;
idReachability_Walk *walkReach;
idReachability_BarrierJump *barrierJumpReach;
idReachability_WaterJump *waterJumpReach;
idReachability_WalkOffLedge *walkOffLedgeReach;
aasTrace_t trace;
// must be able to walk or swim in the first area
if ( !AreaHasFloor( area1num ) && !CanSwimInArea( area1num ) ) {
return false;
}
if ( !AreaHasFloor( area2num ) && !CanSwimInArea( area2num ) ) {
return false;
}
area1 = &file->areas[area1num];
area2 = &file->areas[area2num];
// if the areas are not near anough in the x-y direction
for ( i = 0; i < 2; i++ ) {
if ( area1->bounds[0][i] > area2->bounds[1][i] + 2.0f ) {
return false;
}
if ( area1->bounds[1][i] < area2->bounds[0][i] - 2.0f ) {
return false;
}
}
floor_foundReach = false;
floor_bestDist = 99999;
floor_bestLength = 0;
floor_bestArea2FloorEdgeNum = 0;
water_foundReach = false;
water_bestDist = 99999;
water_bestLength = 0;
water_bestArea2FloorEdgeNum = 0;
for ( i = 0; i < area1->numFaces; i++ ) {
floorFace1Num = file->faceIndex[area1->firstFace + i];
faceSide1 = floorFace1Num < 0;
floorFace1 = &file->faces[abs(floorFace1Num)];
// if this isn't a floor face
if ( !(floorFace1->flags & FACE_FLOOR) ) {
// if we can swim in the first area
if ( CanSwimInArea( area1num ) ) {
// face plane must be more or less horizontal
plane = &file->planeList[ floorFace1->planeNum ^ (!faceSide1) ];
if ( plane->Normal() * file->settings.invGravityDir < file->settings.minFloorCos ) {
continue;
}
}
else {
// if we can't swim in the area it must be a ground face
continue;
}
}
for ( k = 0; k < floorFace1->numEdges; k++ ) {
edge1Num = file->edgeIndex[floorFace1->firstEdge + k];
side1 = (edge1Num < 0);
// NOTE: for water faces we must take the side area 1 is on into
// account because the face is shared and doesn't have to be oriented correctly
if ( !(floorFace1->flags & FACE_FLOOR) ) {
side1 = (side1 == faceSide1);
}
edge1Num = abs(edge1Num);
edge1 = &file->edges[edge1Num];
// vertices of the edge
v1 = file->vertices[edge1->vertexNum[!side1]];
v2 = file->vertices[edge1->vertexNum[side1]];
// get a vertical plane through the edge
// NOTE: normal is pointing into area 2 because the face edges are stored counter clockwise
edgeVec = v2 - v1;
normal = edgeVec.Cross( file->settings.invGravityDir );
normal.Normalize();
dist = normal * v1;
// check the faces from the second area
for ( j = 0; j < area2->numFaces; j++ ) {
floorFace2 = &file->faces[abs(file->faceIndex[area2->firstFace + j])];
// must be a ground face
if ( !(floorFace2->flags & FACE_FLOOR) ) {
continue;
}
// check the edges of this ground face
for ( l = 0; l < floorFace2->numEdges; l++ ) {
edge2Num = abs(file->edgeIndex[floorFace2->firstEdge + l]);
edge2 = &file->edges[edge2Num];
// vertices of the edge
v3 = file->vertices[edge2->vertexNum[0]];
v4 = file->vertices[edge2->vertexNum[1]];
// check the distance between the two points and the vertical plane through the edge of area1
diff = normal * v3 - dist;
if ( diff < -0.2f || diff > 0.2f ) {
continue;
}
diff = normal * v4 - dist;
if ( diff < -0.2f || diff > 0.2f ) {
continue;
}
// project the two ground edges into the step side plane
// and calculate the shortest distance between the two
// edges if they overlap in the direction orthogonal to
// the gravity direction
orthogonal = file->settings.invGravityDir.Cross( normal );
invGravityDot = file->settings.invGravityDir * file->settings.invGravityDir;
orthogonalDot = orthogonal * orthogonal;
// projection into the step plane
// NOTE: since gravity is vertical this is just the z coordinate
y1 = v1[2];//(v1 * file->settings.invGravity) / invGravityDot;
y2 = v2[2];//(v2 * file->settings.invGravity) / invGravityDot;
y3 = v3[2];//(v3 * file->settings.invGravity) / invGravityDot;
y4 = v4[2];//(v4 * file->settings.invGravity) / invGravityDot;
x1 = (v1 * orthogonal) / orthogonalDot;
x2 = (v2 * orthogonal) / orthogonalDot;
x3 = (v3 * orthogonal) / orthogonalDot;
x4 = (v4 * orthogonal) / orthogonalDot;
if ( x1 > x2 ) {
tmp = x1; x1 = x2; x2 = tmp;
tmp = y1; y1 = y2; y2 = tmp;
tmpv = v1; v1 = v2; v2 = tmpv;
}
if ( x3 > x4 ) {
tmp = x3; x3 = x4; x4 = tmp;
tmp = y3; y3 = y4; y4 = tmp;
tmpv = v3; v3 = v4; v4 = tmpv;
}
// if the two projected edge lines have no overlap
if ( x2 <= x3 || x4 <= x1 ) {
continue;
}
// if the two lines fully overlap
if ( (x1 - 0.5f < x3 && x4 < x2 + 0.5f) && (x3 - 0.5f < x1 && x2 < x4 + 0.5f) ) {
dist1 = y3 - y1;
dist2 = y4 - y2;
p1area1 = v1;
p2area1 = v2;
p1area2 = v3;
p2area2 = v4;
}
else {
// if the points are equal
if ( x1 > x3 - 0.1f && x1 < x3 + 0.1f ) {
dist1 = y3 - y1;
p1area1 = v1;
p1area2 = v3;
}
else if ( x1 < x3 ) {
y = y1 + (x3 - x1) * (y2 - y1) / (x2 - x1);
dist1 = y3 - y;
p1area1 = v3;
p1area1[2] = y;
p1area2 = v3;
}
else {
y = y3 + (x1 - x3) * (y4 - y3) / (x4 - x3);
dist1 = y - y1;
p1area1 = v1;
p1area2 = v1;
p1area2[2] = y;
}
// if the points are equal
if ( x2 > x4 - 0.1f && x2 < x4 + 0.1f ) {
dist2 = y4 - y2;
p2area1 = v2;
p2area2 = v4;
}
else if ( x2 < x4 ) {
y = y3 + (x2 - x3) * (y4 - y3) / (x4 - x3);
dist2 = y - y2;
p2area1 = v2;
p2area2 = v2;
p2area2[2] = y;
}
else {
y = y1 + (x4 - x1) * (y2 - y1) / (x2 - x1);
dist2 = y4 - y;
p2area1 = v4;
p2area1[2] = y;
p2area2 = v4;
}
}
// if both distances are pretty much equal then we take the middle of the points
if ( dist1 > dist2 - 1.0f && dist1 < dist2 + 1.0f ) {
dist = dist1;
start = ( p1area1 + p2area1 ) * 0.5f;
end = ( p1area2 + p2area2 ) * 0.5f;
}
else if (dist1 < dist2) {
dist = dist1;
start = p1area1;
end = p1area2;
}
else {
dist = dist2;
start = p2area1;
end = p2area2;
}
// get the length of the overlapping part of the edges of the two areas
length = (p2area2 - p1area2).Length();
if ( floorFace1->flags & FACE_FLOOR ) {
// if the vertical distance is smaller
if ( dist < floor_bestDist ||
// or the vertical distance is pretty much the same
// but the overlapping part of the edges is longer
(dist < floor_bestDist + 1.0f && length > floor_bestLength) ) {
floor_bestDist = dist;
floor_bestLength = length;
floor_foundReach = true;
floor_bestArea1FloorEdgeNum = edge1Num;
floor_bestArea2FloorEdgeNum = edge2Num;
floor_bestFace1 = floorFace1;
floor_bestStart = start;
floor_bestNormal = normal;
floor_bestEnd = end;
}
}
else {
// if the vertical distance is smaller
if ( dist < water_bestDist ||
//or the vertical distance is pretty much the same
//but the overlapping part of the edges is longer
(dist < water_bestDist + 1.0f && length > water_bestLength) ) {
water_bestDist = dist;
water_bestLength = length;
water_foundReach = true;
water_bestArea1FloorEdgeNum = edge1Num;
water_bestArea2FloorEdgeNum = edge2Num;
water_bestFace1 = floorFace1;
water_bestStart = start; // best start point in area1
water_bestNormal = normal; // normal is pointing into area2
water_bestEnd = end; // best point towards area2
}
}
}
}
}
}
//
// NOTE: swim reachabilities should already be filtered out
//
// Steps
//
// ---------
// | step height -> TFL_WALK
// --------|
//
// ---------
// ~~~~~~~~| step height and low water -> TFL_WALK
// --------|
//
// ~~~~~~~~~~~~~~~~~~
// ---------
// | step height and low water up to the step -> TFL_WALK
// --------|
//
// check for a step reachability
if ( floor_foundReach ) {
// if area2 is higher but lower than the maximum step height
// NOTE: floor_bestDist >= 0 also catches equal floor reachabilities
if ( floor_bestDist >= 0 && floor_bestDist < file->settings.maxStepHeight ) {
// create walk reachability from area1 to area2
walkReach = new idReachability_Walk();
walkReach->travelType = TFL_WALK;
walkReach->toAreaNum = area2num;
walkReach->fromAreaNum = area1num;
walkReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
walkReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
walkReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
walkReach->travelTime = 0;
if ( area2->flags & AREA_CROUCH ) {
walkReach->travelTime += file->settings.tt_startCrouching;
}
AddReachabilityToArea( walkReach, area1num );
return true;
}
}
//
// Water Jumps
//
// ---------
// |
// ~~~~~~~~|
// |
// | higher than step height and water up to waterjump height -> TFL_WATERJUMP
// --------|
//
// ~~~~~~~~~~~~~~~~~~
// ---------
// |
// |
// |
// | higher than step height and low water up to the step -> TFL_WATERJUMP
// --------|
//
// check for a waterjump reachability
if ( water_foundReach ) {
// get a test point a little bit towards area1
testPoint = water_bestEnd - INSIDEUNITS * water_bestNormal;
// go down the maximum waterjump height
testPoint[2] -= file->settings.maxWaterJumpHeight;
// if there IS water the sv_maxwaterjump height below the bestend point
if ( area1->flags & AREA_LIQUID ) {
// don't create rediculous water jump reachabilities from areas very far below the water surface
if ( water_bestDist < file->settings.maxWaterJumpHeight + 24 ) {
// water jumping from or towards a crouch only areas is not possible
if ( !(area1->flags & AREA_CROUCH) && !(area2->flags & AREA_CROUCH) ) {
// create water jump reachability from area1 to area2
waterJumpReach = new idReachability_WaterJump();
waterJumpReach->travelType = TFL_WATERJUMP;
waterJumpReach->toAreaNum = area2num;
waterJumpReach->fromAreaNum = area1num;
waterJumpReach->start = water_bestStart;
waterJumpReach->end = water_bestEnd + INSIDEUNITS_WATERJUMP * water_bestNormal;
waterJumpReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
waterJumpReach->travelTime = file->settings.tt_waterJump;
AddReachabilityToArea( waterJumpReach, area1num );
return true;
}
}
}
}
//
// Barrier Jumps
//
// ---------
// |
// |
// |
// | higher than max step height lower than max barrier height -> TFL_BARRIERJUMP
// --------|
//
// ---------
// |
// |
// |
// ~~~~~~~~| higher than max step height lower than max barrier height
// --------| and a thin layer of water in the area to jump from -> TFL_BARRIERJUMP
//
// check for a barrier jump reachability
if ( floor_foundReach ) {
//if area2 is higher but lower than the maximum barrier jump height
if ( floor_bestDist > 0 && floor_bestDist < file->settings.maxBarrierHeight ) {
//if no water in area1 or a very thin layer of water on the ground
if ( !water_foundReach || (floor_bestDist - water_bestDist < 16) ) {
// cannot perform a barrier jump towards or from a crouch area
if ( !(area1->flags & AREA_CROUCH) && !(area2->flags & AREA_CROUCH) ) {
// create barrier jump reachability from area1 to area2
barrierJumpReach = new idReachability_BarrierJump();
barrierJumpReach->travelType = TFL_BARRIERJUMP;
barrierJumpReach->toAreaNum = area2num;
barrierJumpReach->fromAreaNum = area1num;
barrierJumpReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
barrierJumpReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
barrierJumpReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
barrierJumpReach->travelTime = file->settings.tt_barrierJump;
AddReachabilityToArea( barrierJumpReach, area1num );
return true;
}
}
}
}
//
// Walk and Walk Off Ledge
//
// --------|
// | can walk or step back -> TFL_WALK
// ---------
//
// --------|
// |
// |
// |
// | cannot walk/step back -> TFL_WALKOFFLEDGE
// ---------
//
// --------|
// |
// |~~~~~~~~
// |
// | cannot step back but can waterjump back -> TFL_WALKOFFLEDGE
// --------- FIXME: create TFL_WALK reach??
//
// check for a walk or walk off ledge reachability
if ( floor_foundReach ) {
if ( floor_bestDist < 0 ) {
if ( floor_bestDist > -file->settings.maxStepHeight ) {
// create walk reachability from area1 to area2
walkReach = new idReachability_Walk();
walkReach->travelType = TFL_WALK;
walkReach->toAreaNum = area2num;
walkReach->fromAreaNum = area1num;
walkReach->start = floor_bestStart + INSIDEUNITS_WALKSTART * floor_bestNormal;
walkReach->end = floor_bestEnd + INSIDEUNITS_WALKEND * floor_bestNormal;
walkReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
walkReach->travelTime = 1;
AddReachabilityToArea( walkReach, area1num );
return true;
}
// if no maximum fall height set or less than the max
if ( !file->settings.maxFallHeight || idMath::Fabs(floor_bestDist) < file->settings.maxFallHeight ) {
// trace a bounding box vertically to check for solids
floor_bestEnd += INSIDEUNITS * floor_bestNormal;
start = floor_bestEnd;
start[2] = floor_bestStart[2];
end = floor_bestEnd;
end[2] += 4;
trace.areas = areas;
trace.maxAreas = sizeof(areas) / sizeof(int);
file->Trace( trace, start, end );
// if the trace didn't start in solid and nothing was hit
if ( trace.lastAreaNum && trace.fraction >= 1.0f ) {
// the trace end point must be in the goal area
if ( trace.lastAreaNum == area2num ) {
// don't create reachability if going through a cluster portal
for (i = 0; i < trace.numAreas; i++) {
if ( AreaIsClusterPortal( trace.areas[i] ) ) {
break;
}
}
if ( i >= trace.numAreas ) {
// create a walk off ledge reachability from area1 to area2
walkOffLedgeReach = new idReachability_WalkOffLedge();
walkOffLedgeReach->travelType = TFL_WALKOFFLEDGE;
walkOffLedgeReach->toAreaNum = area2num;
walkOffLedgeReach->fromAreaNum = area1num;
walkOffLedgeReach->start = floor_bestStart;
walkOffLedgeReach->end = floor_bestEnd;
walkOffLedgeReach->edgeNum = abs( floor_bestArea1FloorEdgeNum );
walkOffLedgeReach->travelTime = file->settings.tt_startWalkOffLedge + idMath::Fabs(floor_bestDist) * 50 / file->settings.gravityValue;
AddReachabilityToArea( walkOffLedgeReach, area1num );
return true;
}
}
}
}
}
}
return false;
}
/*
================
idAASReach::Reachability_WalkOffLedge
================
*/
void idAASReach::Reachability_WalkOffLedge( int areaNum ) {
int i, j, faceNum, edgeNum, side, reachAreaNum, p, areas[10];
aasArea_t *area;
aasFace_t *face;
aasEdge_t *edge;
idPlane *plane;
idVec3 v1, v2, mid, dir, testEnd;
idReachability_WalkOffLedge *reach;
aasTrace_t trace;
if ( !AreaHasFloor( areaNum ) || CanSwimInArea( areaNum ) ) {
return;
}
area = &file->areas[areaNum];
for ( i = 0; i < area->numFaces; i++ ) {
faceNum = file->faceIndex[area->firstFace + i];
face = &file->faces[abs(faceNum)];
// face must be a floor face
if ( !(face->flags & FACE_FLOOR) ) {
continue;
}
for ( j = 0; j < face->numEdges; j++ ) {
edgeNum = file->edgeIndex[face->firstEdge + j];
edge = &file->edges[abs(edgeNum)];
//if ( !(edge->flags & EDGE_LEDGE) ) {
// continue;
//}
side = edgeNum < 0;
v1 = file->vertices[edge->vertexNum[side]];
v2 = file->vertices[edge->vertexNum[!side]];
plane = &file->planeList[face->planeNum ^ INTSIGNBITSET(faceNum) ];
// get the direction into the other area
dir = plane->Normal().Cross( v2 - v1 );
dir.Normalize();
mid = ( v1 + v2 ) * 0.5f;
testEnd = mid + INSIDEUNITS_WALKEND * dir;
testEnd[2] -= file->settings.maxFallHeight + 1.0f;
trace.areas = areas;
trace.maxAreas = sizeof(areas) / sizeof(int);
file->Trace( trace, mid, testEnd );
reachAreaNum = trace.lastAreaNum;
if ( !reachAreaNum || reachAreaNum == areaNum ) {
continue;
}
if ( idMath::Fabs( mid[2] - trace.endpos[2] ) > file->settings.maxFallHeight ) {
continue;
}
if ( !AreaHasFloor( reachAreaNum ) && !CanSwimInArea( reachAreaNum ) ) {
continue;
}
if ( ReachabilityExists( areaNum, reachAreaNum) ) {
continue;
}
// if not going through a cluster portal
for ( p = 0; p < trace.numAreas; p++ ) {
if ( AreaIsClusterPortal( trace.areas[p] ) ) {
break;
}
}
if ( p < trace.numAreas ) {
continue;
}
reach = new idReachability_WalkOffLedge();
reach->travelType = TFL_WALKOFFLEDGE;
reach->toAreaNum = reachAreaNum;
reach->fromAreaNum = areaNum;
reach->start = mid;
reach->end = trace.endpos;
reach->edgeNum = abs( edgeNum );
reach->travelTime = file->settings.tt_startWalkOffLedge + idMath::Fabs(mid[2] - trace.endpos[2]) * 50 / file->settings.gravityValue;
AddReachabilityToArea( reach, areaNum );
}
}
}
/*
================
idAASReach::FlagReachableAreas
================
*/
void idAASReach::FlagReachableAreas( idAASCompilerFile *file ) {
int i, numReachableAreas;
numReachableAreas = 0;
for ( i = 1; i < file->areas.Num(); i++ ) {
if ( ( file->areas[i].flags & ( AREA_FLOOR | AREA_LADDER ) ) ||
( file->areas[i].contents & AREACONTENTS_WATER ) ) {
file->areas[i].flags |= AREA_REACHABLE_WALK;
}
if ( file->GetSettings().allowFlyReachabilities ) {
file->areas[i].flags |= AREA_REACHABLE_FLY;
}
numReachableAreas++;
}
common->Printf( "%6d reachable areas\n", numReachableAreas );
}
/*
================
idAASReach::Build
================
*/
bool idAASReach::Build( const idMapFile *mapFile, idAASCompilerFile *file ) {
int i, j, lastPercent, percent;
this->mapFile = mapFile;
this->file = file;
numReachabilities = 0;
common->Printf( "[Reachability]\n" );
// delete all existing reachabilities
file->DeleteReachabilities();
FlagReachableAreas( file );
for ( i = 1; i < file->areas.Num(); i++ ) {
if ( !( file->areas[i].flags & AREA_REACHABLE_WALK ) ) {
continue;
}
if ( file->GetSettings().allowSwimReachabilities ) {
Reachability_Swim( i );
}
Reachability_EqualFloorHeight( i );
}
lastPercent = -1;
for ( i = 1; i < file->areas.Num(); i++ ) {
if ( !( file->areas[i].flags & AREA_REACHABLE_WALK ) ) {
continue;
}
for ( j = 0; j < file->areas.Num(); j++ ) {
if ( i == j ) {
continue;
}
if ( !( file->areas[j].flags & AREA_REACHABLE_WALK ) ) {
continue;
}
if ( ReachabilityExists( i, j ) ) {
continue;
}
if ( Reachability_Step_Barrier_WaterJump_WalkOffLedge( i, j ) ) {
continue;
}
}
//Reachability_WalkOffLedge( i );
percent = 100 * i / file->areas.Num();
if ( percent > lastPercent ) {
common->Printf( "\r%6d%%", percent );
lastPercent = percent;
}
}
if ( file->GetSettings().allowFlyReachabilities ) {
for ( i = 1; i < file->areas.Num(); i++ ) {
Reachability_Fly( i );
}
}
file->LinkReversedReachability();
common->Printf( "\r%6d reachabilities\n", numReachabilities );
return true;
}
+303
View File
@@ -0,0 +1,303 @@
/*
===========================================================================
Quake 4 Reconstructed GPL Source Code
Copyright (C) 2026 Justin Marshall(IceColdDuke).
===========================================================================
*/
/*
===============================================================================
Tools-DLL copy of idAASSettings.
The retail executable and Toolsx86.dll each contain the settings methods
they use. Keep this implementation in the tools target only: it combines
the Quake 4 PDB/decompiler behavior with the tool-only FromDict and
ValidEntity routines evidenced by the retail Toolsx86.dll strings.
===============================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASFile.h"
#if defined( _M_IX86 )
static_assert( sizeof( idAASSettings ) == 240, "Quake 4 idAASSettings ABI drift" );
#endif
idAASSettings::idAASSettings( void ) {
numBoundingBoxes = 1;
boundingBoxes[0] = idBounds( idVec3( -16, -16, 0 ), idVec3( 16, 16, 72 ) );
usePatches = false;
writeBrushMap = false;
playerFlood = false;
noOptimize = false;
allowSwimReachabilities = false;
allowFlyReachabilities = false;
generateTacticalFeatures = false;
iAASOnly = 0;
fileExtension = "aas48";
gravity.Set( 0, 0, -1066 );
gravityDir = gravity;
gravityValue = gravityDir.Normalize();
invGravityDir = -gravityDir;
maxStepHeight = 14.0f;
maxBarrierHeight = 32.0f;
maxWaterJumpHeight = 20.0f;
maxFallHeight = 64.0f;
minFloorCos = 0.7f;
tt_barrierJump = 100;
tt_startCrouching = 100;
tt_waterJump = 100;
tt_startWalkOffLedge = 100;
debugColor.Set( 1, 0, 0, 1 );
debugDraw = true;
}
bool idAASSettings::ParseBool( Lexer &src, bool &value ) {
if ( !src.ExpectTokenString( "=" ) ) {
return false;
}
value = src.ParseBool();
return true;
}
bool idAASSettings::ParseInt( Lexer &src, int &value ) {
if ( !src.ExpectTokenString( "=" ) ) {
return false;
}
value = src.ParseInt();
return true;
}
bool idAASSettings::ParseFloat( Lexer &src, float &value ) {
if ( !src.ExpectTokenString( "=" ) ) {
return false;
}
value = src.ParseFloat();
return true;
}
bool idAASSettings::ParseVector( Lexer &src, idVec3 &value ) {
return src.ExpectTokenString( "=" ) && src.Parse1DMatrix( 3, value.ToFloatPtr() );
}
bool idAASSettings::ParseBBoxes( Lexer &src ) {
idToken token;
idBounds bounds;
numBoundingBoxes = 0;
if ( !src.ExpectTokenString( "{" ) ) {
return false;
}
while ( src.ReadToken( &token ) ) {
if ( token == "}" ) {
return numBoundingBoxes > 0;
}
if ( numBoundingBoxes >= MAX_AAS_BOUNDING_BOXES ) {
src.Error( "more than %d AAS bounding boxes", MAX_AAS_BOUNDING_BOXES );
return false;
}
src.UnreadToken( &token );
if ( !src.Parse1DMatrix( 3, bounds[0].ToFloatPtr() ) ||
!src.ExpectTokenString( "-" ) ||
!src.Parse1DMatrix( 3, bounds[1].ToFloatPtr() ) ) {
return false;
}
boundingBoxes[numBoundingBoxes++] = bounds;
}
return false;
}
bool idAASSettings::FromParser( Lexer &src ) {
idToken token;
if ( !src.ExpectTokenString( "{" ) ) {
return false;
}
while ( src.ReadToken( &token ) ) {
if ( token == "}" ) {
break;
}
if ( token == "bboxes" ) { if ( !ParseBBoxes( src ) ) return false; }
else if ( token == "usePatches" ) { if ( !ParseBool( src, usePatches ) ) return false; }
else if ( token == "writeBrushMap" ) { if ( !ParseBool( src, writeBrushMap ) ) return false; }
else if ( token == "playerFlood" ) { if ( !ParseBool( src, playerFlood ) ) return false; }
else if ( token == "allowSwimReachabilities" ) { if ( !ParseBool( src, allowSwimReachabilities ) ) return false; }
else if ( token == "allowFlyReachabilities" ) { if ( !ParseBool( src, allowFlyReachabilities ) ) return false; }
else if ( token == "generateTacticalFeatures" ) { if ( !ParseBool( src, generateTacticalFeatures ) ) return false; }
else if ( token == "fileExtension" ) {
if ( !src.ExpectTokenString( "=" ) || !src.ExpectTokenType( TT_STRING, 0, &token ) ) return false;
fileExtension = token;
}
else if ( token == "gravity" ) {
if ( !ParseVector( src, gravity ) ) return false;
gravityDir = gravity;
gravityValue = gravityDir.Normalize();
invGravityDir = -gravityDir;
}
else if ( token == "maxStepHeight" ) { if ( !ParseFloat( src, maxStepHeight ) ) return false; }
else if ( token == "maxBarrierHeight" ) { if ( !ParseFloat( src, maxBarrierHeight ) ) return false; }
else if ( token == "maxWaterJumpHeight" ) { if ( !ParseFloat( src, maxWaterJumpHeight ) ) return false; }
else if ( token == "maxFallHeight" ) { if ( !ParseFloat( src, maxFallHeight ) ) return false; }
else if ( token == "minFloorCos" ) { if ( !ParseFloat( src, minFloorCos ) ) return false; }
else if ( token == "tt_barrierJump" ) { if ( !ParseInt( src, tt_barrierJump ) ) return false; }
else if ( token == "tt_startCrouching" ) { if ( !ParseInt( src, tt_startCrouching ) ) return false; }
else if ( token == "tt_waterJump" ) { if ( !ParseInt( src, tt_waterJump ) ) return false; }
else if ( token == "tt_startWalkOffLedge" ) { if ( !ParseInt( src, tt_startWalkOffLedge ) ) return false; }
else {
src.Error( "invalid token '%s'", token.c_str() );
return false;
}
}
if ( numBoundingBoxes <= 0 ) {
src.Error( "no valid bounding box" );
return false;
}
const idDict *aasDef = gameEdit ? gameEdit->FindEntityDefDict( fileExtension, false ) : NULL;
if ( aasDef ) {
idVec3 color;
if ( aasDef->GetVector( "debugColor", "1.0 0.0 0.0", color ) ) {
debugColor.Set( color.x, color.y, color.z, 1.0f );
}
aasDef->GetBool( "debugDraw", "1", debugDraw );
aasDef->GetBool( "generateTacticalFeatures", "0", generateTacticalFeatures );
}
return true;
}
bool idAASSettings::FromFile( const idStr &fileName ) {
Lexer src( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
common->Printf( "loading %s\n", fileName.c_str() );
if ( !src.LoadFile( fileName.c_str() ) ) {
common->Warning( "couldn't load %s", fileName.c_str() );
return false;
}
if ( !src.ExpectTokenString( "settings" ) ) {
common->Warning( "%s is not a settings file", fileName.c_str() );
return false;
}
return FromParser( src );
}
bool idAASSettings::FromDict( const char *name, const idDict *dict ) {
idBounds bounds;
idVec3 color;
if ( !dict->GetVector( "mins", "0 0 0", bounds[0] ) ) common->Error( "Missing 'mins' in entityDef '%s'", name );
if ( !dict->GetVector( "maxs", "0 0 0", bounds[1] ) ) common->Error( "Missing 'maxs' in entityDef '%s'", name );
numBoundingBoxes = 1;
boundingBoxes[0] = bounds;
if ( !dict->GetBool( "usePatches", "0", usePatches ) ) common->Error( "Missing 'usePatches' in entityDef '%s'", name );
if ( !dict->GetBool( "writeBrushMap", "0", writeBrushMap ) ) common->Error( "Missing 'writeBrushMap' in entityDef '%s'", name );
if ( !dict->GetBool( "playerFlood", "0", playerFlood ) ) common->Error( "Missing 'playerFlood' in entityDef '%s'", name );
if ( !dict->GetBool( "allowSwimReachabilities", "0", allowSwimReachabilities ) ) common->Error( "Missing 'allowSwimReachabilities' in entityDef '%s'", name );
if ( !dict->GetBool( "allowFlyReachabilities", "0", allowFlyReachabilities ) ) common->Error( "Missing 'allowFlyReachabilities' in entityDef '%s'", name );
if ( !dict->GetString( "fileExtension", "", fileExtension ) ) common->Error( "Missing 'fileExtension' in entityDef '%s'", name );
if ( !dict->GetVector( "gravity", "0 0 -1066", gravity ) ) common->Error( "Missing 'gravity' in entityDef '%s'", name );
gravityDir = gravity;
gravityValue = gravityDir.Normalize();
invGravityDir = -gravityDir;
if ( !dict->GetFloat( "maxStepHeight", "0", maxStepHeight ) ) common->Error( "Missing 'maxStepHeight' in entityDef '%s'", name );
if ( !dict->GetFloat( "maxBarrierHeight", "0", maxBarrierHeight ) ) common->Error( "Missing 'maxBarrierHeight' in entityDef '%s'", name );
if ( !dict->GetFloat( "maxWaterJumpHeight", "0", maxWaterJumpHeight ) ) common->Error( "Missing 'maxWaterJumpHeight' in entityDef '%s'", name );
if ( !dict->GetFloat( "maxFallHeight", "0", maxFallHeight ) ) common->Error( "Missing 'maxFallHeight' in entityDef '%s'", name );
if ( !dict->GetFloat( "minFloorCos", "0", minFloorCos ) ) common->Error( "Missing 'minFloorCos' in entityDef '%s'", name );
if ( !dict->GetInt( "tt_barrierJump", "0", tt_barrierJump ) ) common->Error( "Missing 'tt_barrierJump' in entityDef '%s'", name );
if ( !dict->GetInt( "tt_startCrouching", "0", tt_startCrouching ) ) common->Error( "Missing 'tt_startCrouching' in entityDef '%s'", name );
if ( !dict->GetInt( "tt_waterJump", "0", tt_waterJump ) ) common->Error( "Missing 'tt_waterJump' in entityDef '%s'", name );
if ( !dict->GetInt( "tt_startWalkOffLedge", "0", tt_startWalkOffLedge ) ) common->Error( "Missing 'tt_startWalkOffLedge' in entityDef '%s'", name );
if ( dict->GetVector( "debugColor", "1.0 0.0 0.0", color ) ) debugColor.Set( color.x, color.y, color.z, 1.0f );
dict->GetBool( "debugDraw", "1", debugDraw );
dict->GetBool( "generateTacticalFeatures", "0", generateTacticalFeatures );
return true;
}
bool idAASSettings::WriteToFile( idFile *file ) const {
file->WriteFloatString( "{\n" );
file->WriteFloatString( "\tbboxes\n\t{\n" );
for ( int i = 0; i < numBoundingBoxes; i++ ) {
file->WriteFloatString( "\t\t(%f %f %f)-(%f %f %f)\n",
boundingBoxes[i][0].x, boundingBoxes[i][0].y, boundingBoxes[i][0].z,
boundingBoxes[i][1].x, boundingBoxes[i][1].y, boundingBoxes[i][1].z );
}
file->WriteFloatString( "\t}\n" );
file->WriteFloatString( "\tusePatches = %d\n", usePatches );
file->WriteFloatString( "\twriteBrushMap = %d\n", writeBrushMap );
file->WriteFloatString( "\tplayerFlood = %d\n", playerFlood );
file->WriteFloatString( "\tallowSwimReachabilities = %d\n", allowSwimReachabilities );
file->WriteFloatString( "\tallowFlyReachabilities = %d\n", allowFlyReachabilities );
file->WriteFloatString( "\tgenerateTacticalFeatures = %d\n", generateTacticalFeatures );
file->WriteFloatString( "\tfileExtension = \"%s\"\n", fileExtension.c_str() );
file->WriteFloatString( "\tgravity = (%f %f %f)\n", gravity.x, gravity.y, gravity.z );
file->WriteFloatString( "\tmaxStepHeight = %f\n", maxStepHeight );
file->WriteFloatString( "\tmaxBarrierHeight = %f\n", maxBarrierHeight );
file->WriteFloatString( "\tmaxWaterJumpHeight = %f\n", maxWaterJumpHeight );
file->WriteFloatString( "\tmaxFallHeight = %f\n", maxFallHeight );
file->WriteFloatString( "\tminFloorCos = %f\n", minFloorCos );
file->WriteFloatString( "\ttt_barrierJump = %d\n", tt_barrierJump );
file->WriteFloatString( "\ttt_startCrouching = %d\n", tt_startCrouching );
file->WriteFloatString( "\ttt_waterJump = %d\n", tt_waterJump );
file->WriteFloatString( "\ttt_startWalkOffLedge = %d\n", tt_startWalkOffLedge );
file->WriteFloatString( "}\n" );
return true;
}
bool idAASSettings::ValidForBounds( const idBounds &bounds ) const {
for ( int i = 0; i < 3; i++ ) {
if ( bounds[0][i] < boundingBoxes[0][0][i] || bounds[1][i] > boundingBoxes[0][1][i] ) {
return false;
}
}
return true;
}
bool idAASSettings::ValidEntity( const char *classname, bool *needFlyReachabilities ) const {
if ( needFlyReachabilities ) {
*needFlyReachabilities = false;
}
if ( playerFlood && ( !idStr::Cmp( classname, "info_player_start" ) ||
!idStr::Cmp( classname, "info_player_deathmatch" ) ||
!idStr::Cmp( classname, "func_teleporter" ) ) ) {
return true;
}
const idDict *dict = gameEdit ? gameEdit->FindEntityDefDict( classname, false ) : NULL;
idStr useAAS;
if ( !dict || !dict->GetString( "use_aas", NULL, useAAS ) || fileExtension.Icmp( useAAS ) ) {
return false;
}
idBounds bounds;
idVec3 size;
bounds.Zero();
if ( dict->GetVector( "mins", NULL, bounds[0] ) ) {
dict->GetVector( "maxs", NULL, bounds[1] );
} else if ( dict->GetVector( "size", NULL, size ) ) {
bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z );
}
if ( !ValidForBounds( bounds ) ) {
common->Error( "%s cannot use %s\n", classname, fileExtension.c_str() );
}
if ( needFlyReachabilities ) {
dict->GetBool( "flying", "0", *needFlyReachabilities );
}
return true;
}
float idAASSettings::Radius( float scale ) const {
const idBounds &bounds = boundingBoxes[0];
float radius = idMath::Fabs( bounds[0].x );
if ( idMath::Fabs( bounds[1].x ) > radius ) radius = idMath::Fabs( bounds[1].x );
if ( idMath::Fabs( bounds[0].y ) > radius ) radius = idMath::Fabs( bounds[0].y );
if ( idMath::Fabs( bounds[1].y ) > radius ) radius = idMath::Fabs( bounds[1].y );
return radius * scale;
}
+412
View File
@@ -0,0 +1,412 @@
/*
===========================================================================
Quake 4 Reconstructed GPL Source Code
Copyright (C) 2026 Justin Marshall (IceColdDuke).
Quake 4 tactical AAS generator reconstructed from the public Quake 4 AAS
format, the retail Toolsx86.dll behavior, and the Doom 3 AAS compiler.
===========================================================================
*/
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "AASFile.h"
namespace {
const int TACTICAL_CONTENTS = CONTENTS_SOLID | CONTENTS_MONSTERCLIP | CONTENTS_AAS_SOLID;
const float TACTICAL_WALL_EPSILON = 0.5f;
const float TACTICAL_FEATURE_INSET = 1.0f;
const float TACTICAL_LEAN_DISTANCE = 16.0f;
struct tacticalCandidate_t {
idVec3 origin;
idVec3 normal;
int height;
int flags;
idList<int> areas;
};
class idAASTacticalBuilder {
public:
idAASTacticalBuilder( idAASFile *aasFile, idCollisionModel *worldModel ) :
file( aasFile ), world( worldModel ), settings( aasFile->GetSettings() ) {
}
int Build( const idMapFile &mapFile ) {
file->ClearTactical();
for ( int i = 0; i < file->GetNumAreas(); i++ ) {
aasArea_t &area = file->GetArea( i );
area.numFeatures = 0;
area.firstFeature = 0;
}
AddManualFeatures( mapFile );
AddAutomaticCoverFeatures();
CommitFeatures();
return candidates.Num();
}
private:
bool Trace( const idVec3 &start, const idVec3 &end ) const {
trace_t trace;
collisionModelManager->Translation( &trace, start, end, NULL, mat3_identity,
TACTICAL_CONTENTS, world, vec3_origin, mat3_identity );
return trace.fraction < 1.0f;
}
bool TraceWall( const idVec3 &origin, const idVec3 &normal, float height ) const {
idVec3 start = origin;
start.z += height;
const float distance = settings.Radius() + 12.0f;
return Trace( start, start + normal * distance );
}
int AreaForPoint( const idVec3 &point ) const {
idVec3 raised = point;
raised.z += 1.0f;
int areaNum = file->PointAreaNum( raised );
if ( areaNum > 0 ) {
return areaNum;
}
const idBounds searchBounds( idVec3( -64.0f, -64.0f, -64.0f ), idVec3( 64.0f, 64.0f, 64.0f ) );
return file->PointReachableAreaNum( point, searchBounds, AREA_REACHABLE_WALK, 0 );
}
bool ValidPackedOrigin( const idVec3 &origin ) const {
for ( int i = 0; i < 3; i++ ) {
if ( origin[i] < -32768.0f || origin[i] > 32767.0f ) {
common->Warning( "[AAST] feature at (%g %g %g) is outside the Quake 4 packed coordinate range",
origin.x, origin.y, origin.z );
return false;
}
}
return true;
}
int AddCandidate( const idVec3 &inOrigin, const idVec3 &inNormal, int height, int flags, int areaNum ) {
if ( flags == 0 || !ValidPackedOrigin( inOrigin ) ) {
return -1;
}
idVec3 normal = inNormal;
normal.z = 0.0f;
if ( normal.Normalize() == 0.0f ) {
normal.Set( 1.0f, 0.0f, 0.0f );
}
height = idMath::ClampInt( 0, 255, height );
for ( int i = 0; i < candidates.Num(); i++ ) {
tacticalCandidate_t &candidate = candidates[i];
if ( ( candidate.origin - inOrigin ).LengthSqr() > Square( 3.0f ) || candidate.normal * normal < 0.98f ) {
continue;
}
candidate.flags |= flags;
candidate.height = Max( candidate.height, height );
if ( areaNum > 0 ) {
candidate.areas.AddUnique( areaNum );
}
return i;
}
tacticalCandidate_t candidate;
candidate.origin = inOrigin;
candidate.normal = normal;
candidate.height = height;
candidate.flags = flags;
if ( areaNum > 0 ) {
candidate.areas.Append( areaNum );
}
return candidates.Append( candidate );
}
void AddManualFeatures( const idMapFile &mapFile ) {
for ( int i = 0; i < mapFile.GetNumEntities(); i++ ) {
const idDict &dict = mapFile.GetEntity( i )->epairs;
if ( idStr::Icmp( dict.GetString( "classname" ), "info_tactical_feature" ) != 0 ) {
continue;
}
const idVec3 origin = dict.GetVector( "origin", "0 0 0" );
const float angle = dict.GetFloat( "angle", "0" );
const idVec3 normal = idAngles( 0.0f, angle, 0.0f ).ToForward();
int height = dict.GetInt( "height", "72" );
int flags = dict.GetInt( "flags", "0" );
if ( dict.GetBool( "vantage", "0" ) ) {
flags |= FEATURE_VANTAGE;
}
if ( dict.GetBool( "pinch", "0" ) ) {
flags |= FEATURE_PINCH;
}
if ( dict.GetBool( "cover", "0" ) ) {
flags |= FEATURE_COVER;
}
if ( dict.GetBool( "lean_left", "0" ) ) {
flags |= FEATURE_COVER | FEATURE_LOOK_LEFT;
}
if ( dict.GetBool( "corner_left", "0" ) ) {
flags |= FEATURE_COVER | FEATURE_LOOK_LEFT | FEATURE_CORNER_LEFT;
}
if ( dict.GetBool( "lean_right", "0" ) ) {
flags |= FEATURE_COVER | FEATURE_LOOK_RIGHT;
}
if ( dict.GetBool( "corner_right", "0" ) ) {
flags |= FEATURE_COVER | FEATURE_LOOK_RIGHT | FEATURE_CORNER_RIGHT;
}
if ( height >= 20 && height < 64 ) {
flags |= FEATURE_COVER | FEATURE_LOOK_OVER;
}
const int areaNum = AreaForPoint( origin );
if ( areaNum == 0 ) {
common->Warning( "[AAST] info_tactical_feature at (%g %g %g) is not in an AAS area",
origin.x, origin.y, origin.z );
continue;
}
AddCandidate( origin, normal, height, flags, areaNum );
}
}
bool FindSolidWallPlane( int areaNum, const idVec3 &start, const idVec3 &end, idPlane &wallPlane ) const {
const aasArea_t &area = file->GetArea( areaNum );
for ( int i = 0; i < area.numFaces; i++ ) {
const int signedFaceNum = file->GetFaceIndex( area.firstFace + i );
const aasFace_t &face = file->GetFace( abs( signedFaceNum ) );
if ( !( face.flags & FACE_SOLID ) ) {
continue;
}
const int orientedPlaneNum = face.planeNum ^ ( signedFaceNum < 0 ? 1 : 0 );
const idPlane &plane = file->GetPlane( orientedPlaneNum );
if ( idMath::Fabs( plane.Normal().z ) > 0.25f ) {
continue;
}
if ( idMath::Fabs( plane.Distance( start ) ) <= TACTICAL_WALL_EPSILON &&
idMath::Fabs( plane.Distance( end ) ) <= TACTICAL_WALL_EPSILON ) {
wallPlane = plane;
return true;
}
}
return false;
}
void TestCoverPoint( int areaNum, const idVec3 &point, const idPlane &wallPlane ) {
idVec3 wallNormal = -wallPlane.Normal();
wallNormal.z = 0.0f;
if ( wallNormal.Normalize() == 0.0f ) {
return;
}
idVec3 origin = point + wallPlane.Normal() * TACTICAL_FEATURE_INSET;
int coverHeight = 0;
for ( int height = 20; height <= 72; height += 4 ) {
if ( TraceWall( origin, wallNormal, static_cast<float>( height ) ) ) {
coverHeight = height;
}
}
if ( coverHeight < 20 ) {
return;
}
int flags = FEATURE_COVER;
if ( coverHeight < 68 ) {
flags |= FEATURE_LOOK_OVER;
AddCandidate( origin, wallNormal, coverHeight, flags, areaNum );
return;
}
coverHeight = 72;
const idVec3 up( 0.0f, 0.0f, 1.0f );
const idVec3 right = wallNormal.Cross( up );
const float lookHeight = static_cast<float>( coverHeight ) - TACTICAL_LEAN_DISTANCE;
idVec3 lookOrigin = origin;
lookOrigin.z += lookHeight;
const idVec3 leftLook = lookOrigin - right * TACTICAL_LEAN_DISTANCE;
if ( !Trace( lookOrigin, leftLook ) && !TraceWall( origin - right * TACTICAL_LEAN_DISTANCE, wallNormal, lookHeight ) ) {
flags |= FEATURE_LOOK_LEFT | FEATURE_CORNER_LEFT;
}
const idVec3 rightLook = lookOrigin + right * TACTICAL_LEAN_DISTANCE;
if ( !Trace( lookOrigin, rightLook ) && !TraceWall( origin + right * TACTICAL_LEAN_DISTANCE, wallNormal, lookHeight ) ) {
flags |= FEATURE_LOOK_RIGHT | FEATURE_CORNER_RIGHT;
}
if ( flags & ( FEATURE_LOOK_LEFT | FEATURE_LOOK_RIGHT ) ) {
AddCandidate( origin, wallNormal, coverHeight, flags, areaNum );
}
}
void AddAutomaticCoverFeatures() {
for ( int areaNum = 1; areaNum < file->GetNumAreas(); areaNum++ ) {
const aasArea_t &area = file->GetArea( areaNum );
if ( !( area.flags & AREA_FLOOR ) || ( area.flags & AREA_LIQUID ) ) {
continue;
}
for ( int faceOffset = 0; faceOffset < area.numFaces; faceOffset++ ) {
const int signedFaceNum = file->GetFaceIndex( area.firstFace + faceOffset );
const aasFace_t &floorFace = file->GetFace( abs( signedFaceNum ) );
if ( !( floorFace.flags & FACE_FLOOR ) ) {
continue;
}
for ( int edgeOffset = 0; edgeOffset < floorFace.numEdges; edgeOffset++ ) {
const int signedEdgeNum = file->GetEdgeIndex( floorFace.firstEdge + edgeOffset );
const aasEdge_t &edge = file->GetEdge( abs( signedEdgeNum ) );
const idVec3 start = file->GetVertex( edge.vertexNum[0] );
const idVec3 end = file->GetVertex( edge.vertexNum[1] );
idPlane wallPlane;
if ( !FindSolidWallPlane( areaNum, start, end, wallPlane ) ) {
continue;
}
idVec3 edgeDirection = end - start;
edgeDirection.z = 0.0f;
const float edgeLength = edgeDirection.Normalize();
if ( edgeLength < 4.0f ) {
continue;
}
const float inset = Min( 8.0f, edgeLength * 0.25f );
TestCoverPoint( areaNum, start + edgeDirection * inset, wallPlane );
TestCoverPoint( areaNum, end - edgeDirection * inset, wallPlane );
const int segments = Max( 1, idMath::Ftoi( edgeLength / 96.0f ) );
for ( int sample = 1; sample < segments; sample++ ) {
TestCoverPoint( areaNum, start + edgeDirection * ( edgeLength * sample / segments ), wallPlane );
}
}
}
}
}
static unsigned char PackNormal( float value ) {
const int packed = idMath::Ftoi( ( value + 1.0f ) * 127.0f + 0.5f );
return static_cast<unsigned char>( idMath::ClampInt( 0, 254, packed ) );
}
void CommitFeatures() {
idList<int> featureNumbers;
featureNumbers.SetNum( candidates.Num() );
for ( int i = 0; i < candidates.Num(); i++ ) {
const tacticalCandidate_t &candidate = candidates[i];
aasFeature_t feature;
memset( &feature, 0, sizeof( feature ) );
feature.x = static_cast<short>( idMath::Ftoi( candidate.origin.x ) );
feature.y = static_cast<short>( idMath::Ftoi( candidate.origin.y ) );
feature.z = static_cast<short>( idMath::Ftoi( candidate.origin.z ) );
feature.flags = static_cast<unsigned short>( candidate.flags );
feature.normalx = PackNormal( candidate.normal.x );
feature.normaly = PackNormal( candidate.normal.y );
feature.height = static_cast<unsigned char>( candidate.height );
featureNumbers[i] = file->AppendFeature( feature );
}
for ( int areaNum = 0; areaNum < file->GetNumAreas(); areaNum++ ) {
aasArea_t &area = file->GetArea( areaNum );
area.firstFeature = static_cast<unsigned short>( file->GetNumFeatureIndexes() );
for ( int candidateNum = 0; candidateNum < candidates.Num(); candidateNum++ ) {
if ( candidates[candidateNum].areas.FindIndex( areaNum ) < 0 ) {
continue;
}
aasIndex_t featureNum = featureNumbers[candidateNum];
file->AppendFeatureIndex( featureNum );
area.numFeatures++;
}
}
}
idAASFile *file;
idCollisionModel *world;
idAASSettings &settings;
idList<tacticalCandidate_t> candidates;
};
static idStr TacticalMapName( const char *argument ) {
idStr mapName = argument;
mapName.BackSlashesToSlashes();
mapName.StripFileExtension();
if ( mapName.Icmpn( "maps/", 5 ) != 0 ) {
mapName = "maps/" + mapName;
}
return mapName;
}
}
void RunAASTactical_f( const idCmdArgs &args ) {
if ( args.Argc() != 2 ) {
common->Printf( "runAASTactical <mapfile>\n" );
return;
}
common->ClearWarnings( "generating tactical AAS features" );
common->SetRefreshOnPrint( true );
common->Printf( "[AAST] Generating Tactical Features...\n" );
const idStr mapName = TacticalMapName( args.Argv( 1 ) );
idStr mapFileName = mapName;
mapFileName.SetFileExtension( "map" );
idMapFile mapFile;
if ( !mapFile.Parse( mapFileName ) ) {
common->Warning( "[AAST] couldn't load map file '%s'", mapFileName.c_str() );
common->SetRefreshOnPrint( false );
common->PrintWarnings();
return;
}
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "disconnect" );
collisionModelManager->LoadMap( &mapFile, false );
idCollisionModel *world = collisionModelManager->LoadModel( mapFile.GetName(), WORLD_MODEL_NAME );
if ( world == NULL ) {
common->Warning( "[AAST] couldn't load collision world for '%s'", mapName.c_str() );
collisionModelManager->FreeMap( mapFile.GetName() );
common->SetRefreshOnPrint( false );
common->PrintWarnings();
return;
}
int totalFeatures = 0;
const idDict *types = gameEdit->FindEntityDefDict( "aas_types", false );
if ( types == NULL ) {
common->Warning( "[AAST] unable to find entityDef 'aas_types'" );
} else {
const idKeyValue *type = types->MatchPrefix( "type" );
while ( type != NULL ) {
const idDict *settingsDict = gameEdit->FindEntityDefDict( type->GetValue(), false );
if ( settingsDict != NULL ) {
idAASSettings settings;
settings.FromDict( type->GetValue(), settingsDict );
if ( settings.generateTacticalFeatures ) {
idStr aasName = mapName;
aasName.SetFileExtension( settings.fileExtension );
idAASFile *file = AASFile->CreateNew();
if ( file->Load( aasName, mapFile.GetGeometryCRC() ) ) {
file->SetSettings( settings );
idAASTacticalBuilder builder( file, world );
const int count = builder.Build( mapFile );
if ( file->Write( aasName, mapFile.GetGeometryCRC() ) ) {
common->Printf( "[AAST] %d Features Generated for %s\n", count, settings.fileExtension.c_str() );
totalFeatures += count;
}
} else {
common->Warning( "[AAST] couldn't load '%s'; run runAAS first", aasName.c_str() );
}
delete file;
}
}
type = types->MatchPrefix( "type", type );
}
}
collisionModelManager->FreeMap( mapFile.GetName() );
common->Printf( "[AAST] %d Features Generated\n", totalFeatures );
common->SetRefreshOnPrint( false );
common->PrintWarnings();
}
+1582
View File
File diff suppressed because it is too large Load Diff
+2151
View File
File diff suppressed because it is too large Load Diff
-469
View File
@@ -1,469 +0,0 @@
function(q4_add_engine_object target)
add_library(${target} OBJECT ${ARGN})
target_include_directories(${target}
PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/renderer/jpeg-6
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis/include
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(${target}
PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_DISABLE_TOOLS
Q4_DISABLE_GL_LOGGING
Q4_DISABLE_TASKKEY_HOOK
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
set_target_properties(${target} PROPERTIES FOLDER "Engine/Seed")
endfunction()
file(GLOB_RECURSE Q4_AAS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/aas/*.cpp
)
set(Q4_AAS_FILE_SOURCE ${PROJECT_SOURCE_DIR}/aas/AASFile.cpp)
set(Q4_AAS_COMPILER_SOURCES
${PROJECT_SOURCE_DIR}/aas/AASSettingsTools.cpp
${PROJECT_SOURCE_DIR}/aas/AASTactical.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_file.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_gravity.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_ledge.cpp
${PROJECT_SOURCE_DIR}/aas/AASBuild_merge.cpp
${PROJECT_SOURCE_DIR}/aas/AASCluster.cpp
${PROJECT_SOURCE_DIR}/aas/AASReach.cpp
${PROJECT_SOURCE_DIR}/aas/Brush.cpp
${PROJECT_SOURCE_DIR}/aas/BrushBSP.cpp
)
list(REMOVE_ITEM Q4_AAS_SOURCES ${Q4_AAS_COMPILER_SOURCES})
file(GLOB_RECURSE Q4_CM_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/cm/*.cpp
)
set(Q4_CM_MODEL_SOURCE ${PROJECT_SOURCE_DIR}/cm/CollisionModel.cpp)
set(Q4_CM_LOAD_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_load.cpp)
set(Q4_CM_CONTACTS_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_contacts.cpp)
set(Q4_CM_CONTENTS_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_contents.cpp)
set(Q4_CM_TRACE_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_trace.cpp)
set(Q4_CM_TRANSLATE_SOURCE ${PROJECT_SOURCE_DIR}/cm/collisionmodel_translate.cpp)
list(REMOVE_ITEM Q4_CM_SOURCES ${Q4_CM_MODEL_SOURCE})
file(GLOB Q4_FRAMEWORK_TOP_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/framework/*.cpp)
set(Q4_FRAMEWORK_PLAYER_MODEL_SOURCE ${PROJECT_SOURCE_DIR}/framework/DeclPlayerModel.cpp)
set(Q4_FRAMEWORK_ENGINE_TOP_SOURCES ${Q4_FRAMEWORK_TOP_SOURCES})
# DeclPlayerModel is owned by gamex86.dll in the retail PDB. Keep it out of
# q4xp.exe so the reconstructed compiland and its allocator live in the same
# module that registers DECL_PLAYER_MODEL.
list(REMOVE_ITEM Q4_FRAMEWORK_ENGINE_TOP_SOURCES ${Q4_FRAMEWORK_PLAYER_MODEL_SOURCE})
set(Q4_FRAMEWORK_SESSION_SOURCES
${PROJECT_SOURCE_DIR}/framework/common.cpp
${PROJECT_SOURCE_DIR}/framework/session.cpp
${PROJECT_SOURCE_DIR}/framework/session_menu.cpp
)
set(Q4_FRAMEWORK_EDITFIELD_SOURCE ${PROJECT_SOURCE_DIR}/framework/editfield.cpp)
set(Q4_FRAMEWORK_CONSOLE_SOURCE ${PROJECT_SOURCE_DIR}/framework/console.cpp)
set(Q4_FRAMEWORK_USERCMD_SOURCE ${PROJECT_SOURCE_DIR}/framework/usercmdgen.cpp)
set(Q4_FRAMEWORK_CONSOLE_SOURCES
${Q4_FRAMEWORK_EDITFIELD_SOURCE}
${Q4_FRAMEWORK_CONSOLE_SOURCE}
${Q4_FRAMEWORK_USERCMD_SOURCE}
)
file(GLOB Q4_FRAMEWORK_ASYNC_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/framework/async/*.cpp)
set(Q4_FRAMEWORK_MSGCHANNEL_SOURCE ${PROJECT_SOURCE_DIR}/framework/async/msgchannel.cpp)
list(REMOVE_ITEM Q4_FRAMEWORK_ASYNC_SOURCES ${Q4_FRAMEWORK_MSGCHANNEL_SOURCE})
set(Q4_FRAMEWORK_CORE_SOURCES ${Q4_FRAMEWORK_ENGINE_TOP_SOURCES})
list(REMOVE_ITEM Q4_FRAMEWORK_CORE_SOURCES
${Q4_FRAMEWORK_SESSION_SOURCES}
${Q4_FRAMEWORK_CONSOLE_SOURCES}
)
file(GLOB_RECURSE Q4_UI_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/ui/*.cpp
)
# Retail quake4.exe renderer compilation units. Keep this explicit: the PDB
# records one object for each entry and the list doubles as a boundary audit.
set(Q4_RENDERER_SOURCES
${PROJECT_SOURCE_DIR}/renderer/Cinematic.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_arb.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_arb2.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_common.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_nv10.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_nv20.cpp
${PROJECT_SOURCE_DIR}/renderer/draw_r200.cpp
${PROJECT_SOURCE_DIR}/renderer/GuiModel.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_files.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_init.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_load.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_process.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_program.cpp
${PROJECT_SOURCE_DIR}/renderer/Image_stats.cpp
${PROJECT_SOURCE_DIR}/renderer/Interaction.cpp
${PROJECT_SOURCE_DIR}/renderer/Material.cpp
${PROJECT_SOURCE_DIR}/renderer/MegaTexture.cpp
${PROJECT_SOURCE_DIR}/renderer/Model.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelDecal.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelManager.cpp
${PROJECT_SOURCE_DIR}/renderer/ModelOverlay.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_ase.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_beam.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_liquid.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_lwo.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_ma.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_md3.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_md5.cpp
${PROJECT_SOURCE_DIR}/renderer/Model_sprite.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderEntity.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderSystem.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderSystem_init.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_demo.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_load.cpp
${PROJECT_SOURCE_DIR}/renderer/RenderWorld_portals.cpp
${PROJECT_SOURCE_DIR}/renderer/Shaders.cpp
${PROJECT_SOURCE_DIR}/renderer/rvGLSLShader.cpp
${PROJECT_SOURCE_DIR}/renderer/rvIndexBuffer.cpp
${PROJECT_SOURCE_DIR}/renderer/rvMesh.cpp
${PROJECT_SOURCE_DIR}/renderer/rvPrimBatch.cpp
${PROJECT_SOURCE_DIR}/renderer/rvRenderModelMD5R.cpp
${PROJECT_SOURCE_DIR}/renderer/rvSpecial.cpp
${PROJECT_SOURCE_DIR}/renderer/rvTexRenderTarget.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexBuffer.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexBufferCopy.cpp
${PROJECT_SOURCE_DIR}/renderer/rvVertexFormat.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_backend.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_deform.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_font.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_guisurf.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_light.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_lightrun.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_main.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_orderIndexes.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_polytope.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_render.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_rendertools.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_shadowbounds.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_stencilshadow.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_subview.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_trace.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_trisurf.cpp
${PROJECT_SOURCE_DIR}/renderer/tr_turboshadow.cpp
${PROJECT_SOURCE_DIR}/renderer/VertexCache.cpp
)
# Retail BSE object boundaries recovered from quake4.pdb.
set(Q4_BSE_SOURCES
${PROJECT_SOURCE_DIR}/bse/BSE_Bounds.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Effect.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_EffectTemplate.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Electricity.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Envelopes.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Light.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Manager.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_ParseParticle2.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Particle.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Render.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_Segment.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_SegmentTemplate.cpp
${PROJECT_SOURCE_DIR}/bse/BSE_SpawnDomains.cpp
)
file(GLOB Q4_JPEG_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/renderer/jpeg-6/*.c)
file(GLOB_RECURSE Q4_SOUND_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/sound/*.cpp)
file(GLOB_RECURSE Q4_OGGVORBIS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/sound/OggVorbis/*.c
)
file(GLOB_RECURSE Q4_SYS_SOURCES CONFIGURE_DEPENDS
${PROJECT_SOURCE_DIR}/sys/*.cpp
)
q4_add_engine_object(q4_engine_aas_file ${Q4_AAS_FILE_SOURCE})
q4_add_engine_object(q4_engine_aas ${Q4_AAS_SOURCES})
target_compile_definitions(q4_engine_aas PRIVATE Q4_AAS_LEGACY_SEED)
q4_add_engine_object(q4_engine_cm_model ${Q4_CM_MODEL_SOURCE})
target_compile_definitions(q4_engine_cm_model PRIVATE Q4_CM_MODEL_ONLY)
q4_add_engine_object(q4_engine_cm_load ${Q4_CM_LOAD_SOURCE})
q4_add_engine_object(q4_engine_cm_contacts ${Q4_CM_CONTACTS_SOURCE})
q4_add_engine_object(q4_engine_cm_contents ${Q4_CM_CONTENTS_SOURCE})
q4_add_engine_object(q4_engine_cm_trace ${Q4_CM_TRACE_SOURCE})
q4_add_engine_object(q4_engine_cm_translate ${Q4_CM_TRANSLATE_SOURCE})
q4_add_engine_object(q4_engine_cm_seed ${Q4_CM_SOURCES})
target_compile_definitions(q4_engine_cm_seed PRIVATE Q4_CM_LEGACY_SEED)
set(Q4_FRAMEWORK_CORE_TARGETS)
foreach(source IN LISTS Q4_FRAMEWORK_CORE_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_framework_core_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_FRAMEWORK_CORE_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_framework_core DEPENDS ${Q4_FRAMEWORK_CORE_TARGETS})
set_target_properties(q4_engine_framework_core PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_engine_framework_editfield ${Q4_FRAMEWORK_EDITFIELD_SOURCE})
q4_add_engine_object(q4_engine_framework_console_impl ${Q4_FRAMEWORK_CONSOLE_SOURCE})
q4_add_engine_object(q4_engine_framework_usercmd ${Q4_FRAMEWORK_USERCMD_SOURCE})
add_custom_target(q4_engine_framework_console
DEPENDS
q4_engine_framework_editfield
q4_engine_framework_console_impl
q4_engine_framework_usercmd
)
set_target_properties(q4_engine_framework_console PROPERTIES FOLDER "Engine/Seed")
set(Q4_FRAMEWORK_ASYNC_TARGETS)
foreach(source IN LISTS Q4_FRAMEWORK_ASYNC_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_framework_async_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_FRAMEWORK_ASYNC_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_framework_async DEPENDS ${Q4_FRAMEWORK_ASYNC_TARGETS})
set_target_properties(q4_engine_framework_async PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_engine_framework_msgchannel ${Q4_FRAMEWORK_MSGCHANNEL_SOURCE})
target_compile_definitions(q4_engine_framework_msgchannel PRIVATE Q4_RECON_SDK_MSGQUEUE)
q4_add_engine_object(q4_engine_framework_session ${Q4_FRAMEWORK_SESSION_SOURCES})
foreach(target q4_engine_framework_editfield q4_engine_framework_console_impl q4_engine_framework_usercmd q4_engine_framework_session)
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
endforeach()
set(Q4_UI_TARGETS)
foreach(source IN LISTS Q4_UI_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_ui_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_UI_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_ui DEPENDS ${Q4_UI_TARGETS})
set_target_properties(q4_engine_ui PROPERTIES FOLDER "Engine/Seed")
set(Q4_RENDERER_TARGETS)
foreach(source IN LISTS Q4_RENDERER_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_renderer_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_RENDERER_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_renderer DEPENDS ${Q4_RENDERER_TARGETS})
set_target_properties(q4_engine_renderer PROPERTIES FOLDER "Engine/Seed")
set(Q4_BSE_TARGETS)
foreach(source IN LISTS Q4_BSE_SOURCES)
get_filename_component(stem ${source} NAME_WE)
string(TOLOWER ${stem} stem_lower)
set(target q4_engine_bse_${stem_lower})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_BSE_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_bse DEPENDS ${Q4_BSE_TARGETS})
set_target_properties(q4_engine_bse PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_bse_abi ${PROJECT_SOURCE_DIR}/tests/abi/BSE_ABI.cpp)
target_compile_definitions(q4_bse_abi PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
set_target_properties(q4_bse_abi PROPERTIES FOLDER "Reconstruction/ABI")
q4_add_engine_object(q4_renderer_raven_abi ${PROJECT_SOURCE_DIR}/tests/abi/RendererRaven_ABI.cpp)
target_compile_definitions(q4_renderer_raven_abi PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
set_target_properties(q4_renderer_raven_abi PROPERTIES FOLDER "Reconstruction/ABI")
q4_add_engine_object(q4_thirdparty_jpeg ${Q4_JPEG_SOURCES})
target_include_directories(q4_thirdparty_jpeg PRIVATE ${PROJECT_SOURCE_DIR}/renderer/jpeg-6)
set_target_properties(q4_thirdparty_jpeg PROPERTIES FOLDER "ThirdParty")
set(Q4_SOUND_TARGETS)
foreach(source IN LISTS Q4_SOUND_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_sound_${stem})
q4_add_engine_object(${target} ${source})
target_include_directories(${target} PRIVATE ${PROJECT_SOURCE_DIR}/sound ${PROJECT_SOURCE_DIR}/sys/win32)
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE Q4_RECONSTRUCTED_SOUND)
list(APPEND Q4_SOUND_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_sound DEPENDS ${Q4_SOUND_TARGETS})
set_target_properties(q4_engine_sound PROPERTIES FOLDER "Engine/Seed")
q4_add_engine_object(q4_thirdparty_oggvorbis ${Q4_OGGVORBIS_SOURCES})
target_include_directories(q4_thirdparty_oggvorbis PRIVATE
${PROJECT_SOURCE_DIR}/sound/OggVorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbissrc
)
set_target_properties(q4_thirdparty_oggvorbis PROPERTIES FOLDER "ThirdParty")
set(Q4_SYS_TARGETS)
foreach(source IN LISTS Q4_SYS_SOURCES)
get_filename_component(stem ${source} NAME_WE)
set(target q4_engine_sys_${stem})
q4_add_engine_object(${target} ${source})
target_compile_definitions(${target} PRIVATE Q4_RECON_ENGINE_PRIVATE Q4_RECON_SDK_MSGQUEUE)
list(APPEND Q4_SYS_TARGETS ${target})
endforeach()
add_custom_target(q4_engine_sys DEPENDS ${Q4_SYS_TARGETS})
set_target_properties(q4_engine_sys PROPERTIES FOLDER "Engine/Seed")
add_custom_target(q4_engine_seed
DEPENDS
q4_engine_aas
q4_engine_aas_file
q4_engine_cm_model
q4_engine_cm_load
q4_engine_cm_contacts
q4_engine_cm_contents
q4_engine_cm_trace
q4_engine_cm_translate
q4_engine_cm_seed
q4_engine_framework_core
q4_engine_framework_console
q4_engine_framework_async
q4_engine_framework_msgchannel
q4_engine_framework_session
q4_engine_ui
q4_engine_renderer
q4_engine_bse
q4_thirdparty_jpeg
q4_engine_sound
q4_thirdparty_oggvorbis
q4_engine_sys
)
set_target_properties(q4_engine_seed PROPERTIES FOLDER "Engine")
add_custom_target(q4_reconstruction_foundation
DEPENDS
q4_idlib
q4_engine_aas
q4_engine_aas_file
q4_engine_cm_model
q4_engine_cm_load
q4_engine_cm_contacts
q4_engine_cm_contents
q4_engine_cm_trace
q4_engine_cm_translate
q4_engine_cm_seed
q4_engine_framework_console
q4_engine_framework_core_cmdsystem
q4_engine_framework_core_compressor
q4_engine_framework_core_cvarsystem
q4_engine_framework_core_declaf
q4_engine_framework_core_declentitydef
q4_engine_framework_core_declmanager
q4_engine_framework_core_declpda
q4_engine_framework_core_declskin
q4_engine_framework_core_decltable
q4_engine_framework_core_demofile
q4_engine_framework_core_eventloop
q4_engine_framework_core_file
q4_engine_framework_core_filesystem
q4_engine_framework_core_keyinput
q4_engine_framework_core_unzip
q4_engine_framework_async_asyncnetwork
q4_engine_framework_async_networksystem
q4_engine_framework_msgchannel
q4_engine_ui
q4_thirdparty_jpeg
q4_thirdparty_oggvorbis
)
set_target_properties(q4_reconstruction_foundation PROPERTIES FOLDER "Reconstruction")
# Full reconstructed Win32 engine integration target. The per-compiland
# object targets above remain the source-ownership/ABI audit surface; this
# target compiles the same recovered sources into a runnable executable.
# The editor and compilers live in the external q4_tools target and cross the
# reconstructed retail Tools API rather than being compiled into the engine.
# CURL remains disabled at this reconstruction frontier.
set(Q4_OPENAL_LOADER_SOURCES
${PROJECT_SOURCE_DIR}/openal/idal.cpp
)
add_executable(q4xp WIN32
${PROJECT_SOURCE_DIR}/sys/win32/rc/Quake4.rc
${Q4_AAS_SOURCES}
${Q4_CM_MODEL_SOURCE}
${Q4_CM_SOURCES}
${Q4_FRAMEWORK_ENGINE_TOP_SOURCES}
${Q4_FRAMEWORK_ASYNC_SOURCES}
${Q4_FRAMEWORK_MSGCHANNEL_SOURCE}
${Q4_UI_SOURCES}
${Q4_RENDERER_SOURCES}
${Q4_BSE_SOURCES}
${Q4_JPEG_SOURCES}
${Q4_SOUND_SOURCES}
${Q4_OGGVORBIS_SOURCES}
${Q4_OPENAL_LOADER_SOURCES}
${Q4_SYS_SOURCES}
)
target_include_directories(q4xp PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/renderer/jpeg-6
${PROJECT_SOURCE_DIR}/sound
${PROJECT_SOURCE_DIR}/sys/win32
${PROJECT_SOURCE_DIR}/sound/OggVorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg
${PROJECT_SOURCE_DIR}/sound/OggVorbis/ogg/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbis/include
${PROJECT_SOURCE_DIR}/sound/OggVorbis/vorbissrc
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4xp PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
__DOOM_DLL__
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_RECON_ENGINE_PRIVATE
Q4_RECON_SDK_MSGQUEUE
Q4_DISABLE_TASKKEY_HOOK
Q4_DISABLE_TOOLS
Q4_DISABLE_GL_LOGGING
Q4_RECONSTRUCTED_SOUND
ID_ENABLE_CURL=0
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_link_directories(q4xp PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Lib/x86"
${PROJECT_SOURCE_DIR}/openal/lib
)
target_link_libraries(q4xp PRIVATE
q4_idlib
opengl32
winmm
ws2_32
iphlpapi
dbghelp
comctl32
dinput8
dsound
dxguid
version
)
if(MSVC)
# Keep an address map and symbols beside the reconstructed executable so
# retail-startup crashes can be resolved without enabling the tools DLL.
target_compile_options(q4xp PRIVATE /Zi)
target_link_options(q4xp PRIVATE
/DEBUG:FULL
/PDB:E:/projects/Quake4Alpha/q4xp.pdb
/MAP:E:/projects/Quake4Alpha/q4xp.map
/STACK:16777216,4096
)
endif()
set_target_properties(q4xp PROPERTIES
OUTPUT_NAME q4xp
RUNTIME_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "E:/projects/Quake4Alpha"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "E:/projects/Quake4Alpha"
PDB_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha"
FOLDER "Engine"
)
+1115
View File
File diff suppressed because it is too large Load Diff
-56
View File
@@ -1,56 +0,0 @@
file(GLOB_RECURSE Q4_GAME_SOURCES CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
)
# Callbacks.cpp is generated-style source text included by gamesys/Class.cpp;
# it is not a standalone translation unit in the Quake 4 SDK project.
list(REMOVE_ITEM Q4_GAME_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/gamesys/Callbacks.cpp
)
add_library(gamex86 SHARED
${Q4_GAME_SOURCES}
${PROJECT_SOURCE_DIR}/framework/DeclPlayerModel.cpp
)
target_include_directories(gamex86 PRIVATE
${PROJECT_SOURCE_DIR}
${PROJECT_SOURCE_DIR}/game
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(gamex86 PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
GAME_DLL
Q4SDK
Q4_RECON_RETAIL_UI_MANAGER_ABI
Q4_NO_PUNKBUSTER
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_link_libraries(gamex86 PRIVATE q4_game_idlib winmm)
if(MSVC)
target_compile_options(gamex86 PRIVATE /Zi)
target_link_options(gamex86 PRIVATE
/DEF:${CMAKE_CURRENT_SOURCE_DIR}/game.def
/DEBUG:FULL
/PDB:E:/projects/Quake4Alpha/q4base/gamex86.pdb
)
endif()
set_target_properties(gamex86 PROPERTIES
OUTPUT_NAME gamex86
PREFIX ""
RUNTIME_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha/q4base"
RUNTIME_OUTPUT_DIRECTORY_DEBUG "E:/projects/Quake4Alpha/q4base"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "E:/projects/Quake4Alpha/q4base"
LIBRARY_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha/q4base"
ARCHIVE_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha/q4base"
PDB_OUTPUT_DIRECTORY "E:/projects/Quake4Alpha/q4base"
FOLDER "Game"
)
+713
View File
@@ -0,0 +1,713 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="idLib"
ProjectGUID="{49BEC5C6-B964-417A-851E-808886B57400}"
RootNamespace="idLib"
SccProjectName="Perforce Project"
SccAuxPath=""
SccLocalPath=".."
SccProvider="MSSCCI:NXN alienbrain"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../$(PlatformName)/$(ConfigurationName)"
IntermediateDirectory="$(OutDir)"
ConfigurationType="4"
UseOfMFC="0"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="mssdk/include"
PreprocessorDefinitions="_DEBUG,_WINDOWS,Q4SDK"
MinimalRebuild="FALSE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
EnableFunctionLevelLinking="TRUE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough=""
PrecompiledHeaderFile="$(IntDir)/$(ProjectName)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/$(ProjectName)/"
ObjectFile="$(IntDir)/$(ProjectName)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
BrowseInformationFile="$(IntDir)/$(ProjectName)/"
WarningLevel="4"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="4"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(IntDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="DebugInline|Win32"
OutputDirectory="../$(PlatformName)/$(ConfigurationName)"
IntermediateDirectory="$(OutDir)"
ConfigurationType="4"
UseOfMFC="0"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
InlineFunctionExpansion="1"
AdditionalIncludeDirectories="mssdk/include"
PreprocessorDefinitions="_DEBUG,_WINDOWS,_INLINEDEBUG,Q4SDK"
MinimalRebuild="FALSE"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
BufferSecurityCheck="TRUE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough=""
PrecompiledHeaderFile="$(IntDir)/$(ProjectName)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/$(ProjectName)/"
ObjectFile="$(IntDir)/$(ProjectName)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
BrowseInformation="1"
BrowseInformationFile="$(IntDir)/$(ProjectName)/"
WarningLevel="4"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(IntDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"
ShowProgress="TRUE"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../$(PlatformName)/$(ConfigurationName)"
IntermediateDirectory="$(OutDir)"
ConfigurationType="4"
UseOfMFC="0"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="3"
GlobalOptimizations="TRUE"
InlineFunctionExpansion="1"
EnableIntrinsicFunctions="TRUE"
FavorSizeOrSpeed="0"
OmitFramePointers="FALSE"
OptimizeForProcessor="3"
AdditionalIncludeDirectories="mssdk/include"
PreprocessorDefinitions="NDEBUG,_WINDOWS,_FINAL,Q4SDK"
StringPooling="TRUE"
RuntimeLibrary="0"
BufferSecurityCheck="FALSE"
EnableFunctionLevelLinking="FALSE"
ForceConformanceInForLoopScope="TRUE"
RuntimeTypeInfo="TRUE"
UsePrecompiledHeader="3"
PrecompiledHeaderThrough=""
PrecompiledHeaderFile="$(IntDir)/$(ProjectName)/$(ProjectName).pch"
AssemblerListingLocation="$(IntDir)/$(ProjectName)/"
ObjectFile="$(IntDir)/$(ProjectName)/"
ProgramDataBaseFileName="$(IntDir)/$(ProjectName).pdb"
BrowseInformation="0"
BrowseInformationFile="$(IntDir)/$(ProjectName)/"
WarningLevel="4"
Detect64BitPortabilityProblems="FALSE"
DebugInformationFormat="3"
CompileAs="0"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLibrarianTool"
OutputFile="$(IntDir)/$(ProjectName).lib"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="idLib"
Filter="">
<File
RelativePath="idlib\AutoPtr.h">
</File>
<File
RelativePath="idlib\Base64.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="3"/>
</FileConfiguration>
<FileConfiguration
Name="DebugInline|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="3"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="3"/>
</FileConfiguration>
</File>
<File
RelativePath="idlib\Base64.h">
</File>
<File
RelativePath="idlib\BitMsg.cpp">
</File>
<File
RelativePath="idlib\BitMsg.h">
</File>
<File
RelativePath="idlib\CmdArgs.cpp">
</File>
<File
RelativePath="idlib\CmdArgs.h">
</File>
<File
RelativePath="idlib\Dict.cpp">
</File>
<File
RelativePath="idlib\Dict.h">
</File>
<File
RelativePath="idlib\Heap.cpp">
</File>
<File
RelativePath="idlib\Heap.h">
</File>
<File
RelativePath=".\idlib\LangDict.cpp">
</File>
<File
RelativePath=".\idlib\LangDict.h">
</File>
<File
RelativePath="idlib\Lexer.cpp">
</File>
<File
RelativePath="idlib\Lexer.h">
</File>
<File
RelativePath="idlib\LexerFactory.cpp">
</File>
<File
RelativePath="idlib\LexerFactory.h">
</File>
<File
RelativePath=".\idlib\Lib.cpp">
<FileConfiguration
Name="Debug|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="DebugInline|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32">
<Tool
Name="VCCLCompilerTool"
UsePrecompiledHeader="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\idlib\Lib.h">
</File>
<File
RelativePath="idlib\mapfile.cpp">
</File>
<File
RelativePath="idlib\MapFile.h">
</File>
<File
RelativePath="idlib\Parser.cpp">
</File>
<File
RelativePath="idlib\Parser.h">
</File>
<File
RelativePath="idlib\precompiled.h">
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCustomBuildTool"/>
</FileConfiguration>
<FileConfiguration
Name="DebugInline|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCustomBuildTool"/>
</FileConfiguration>
<FileConfiguration
Name="Release|Win32"
ExcludedFromBuild="TRUE">
<Tool
Name="VCCustomBuildTool"/>
</FileConfiguration>
</File>
<File
RelativePath=".\idlib\rvHeap.cpp">
</File>
<File
RelativePath=".\idlib\rvHeap.h">
</File>
<File
RelativePath=".\idlib\rvHeapArena.cpp">
</File>
<File
RelativePath=".\idlib\rvHeapArena.h">
</File>
<File
RelativePath=".\idlib\rvMemSys.cpp">
</File>
<File
RelativePath=".\idlib\rvMemSys.h">
</File>
<File
RelativePath="idlib\Str.cpp">
</File>
<File
RelativePath="idlib\Str.h">
</File>
<File
RelativePath="idlib\TextCompiler.cpp">
</File>
<File
RelativePath="idlib\TextCompiler.h">
</File>
<File
RelativePath="idlib\Timer.cpp">
</File>
<File
RelativePath="idlib\Timer.h">
</File>
<File
RelativePath=".\idlib\TimingCollection.cpp">
</File>
<File
RelativePath=".\idlib\TimingCollection.h">
</File>
<File
RelativePath="idlib\Token.cpp">
</File>
<File
RelativePath="idlib\Token.h">
</File>
<Filter
Name="BV"
Filter="">
<File
RelativePath="idlib\bv\Bounds.cpp">
</File>
<File
RelativePath="idlib\bv\Bounds.h">
</File>
<File
RelativePath="idlib\bv\Box.cpp">
</File>
<File
RelativePath="idlib\bv\Box.h">
</File>
<File
RelativePath="idlib\bv\Frustum.cpp">
</File>
<File
RelativePath="idlib\bv\Frustum.h">
</File>
<File
RelativePath="idlib\bv\Sphere.cpp">
</File>
<File
RelativePath="idlib\bv\Sphere.h">
</File>
</Filter>
<Filter
Name="Containers"
Filter="">
<File
RelativePath="idlib\containers\BinSearch.h">
</File>
<File
RelativePath=".\idlib\BTree.h">
</File>
<File
RelativePath="idlib\containers\HashIndex.cpp">
</File>
<File
RelativePath="idlib\containers\HashIndex.h">
</File>
<File
RelativePath="idlib\containers\HashTable.h">
</File>
<File
RelativePath="idlib\containers\Hierarchy.h">
</File>
<File
RelativePath="idlib\containers\LinkList.h">
</File>
<File
RelativePath="idlib\containers\List.h">
</File>
<File
RelativePath=".\idlib\containers\Pair.h">
</File>
<File
RelativePath="idlib\containers\PlaneSet.h">
</File>
<File
RelativePath="idlib\containers\Queue.h">
</File>
<File
RelativePath=".\idlib\containers\rvBlockPool.h">
</File>
<File
RelativePath="idlib\containers\Stack.h">
</File>
<File
RelativePath="idlib\containers\StaticList.h">
</File>
<File
RelativePath="idlib\containers\StrList.h">
</File>
<File
RelativePath="idlib\containers\StrPool.h">
</File>
<File
RelativePath="idlib\containers\VectorSet.h">
</File>
</Filter>
<Filter
Name="Geometry"
Filter="">
<File
RelativePath="idlib\geometry\DrawVert.h">
</File>
<File
RelativePath=".\idlib\geometry\JointTransform.cpp">
</File>
<File
RelativePath=".\idlib\geometry\JointTransform.h">
</File>
<File
RelativePath=".\idlib\geometry\rvVertex.h">
</File>
<File
RelativePath="idlib\geometry\Surface.cpp">
</File>
<File
RelativePath="idlib\geometry\Surface.h">
</File>
<File
RelativePath="idlib\geometry\Surface_Patch.cpp">
</File>
<File
RelativePath="idlib\geometry\Surface_Patch.h">
</File>
<File
RelativePath=".\idlib\geometry\Surface_Polytope.cpp">
</File>
<File
RelativePath=".\idlib\geometry\Surface_Polytope.h">
</File>
<File
RelativePath="idlib\geometry\Surface_SweptSpline.cpp">
</File>
<File
RelativePath="idlib\geometry\Surface_SweptSpline.h">
</File>
<File
RelativePath="idlib\geometry\TraceModel.cpp">
</File>
<File
RelativePath="idlib\geometry\TraceModel.h">
</File>
<File
RelativePath="idlib\geometry\Winding.cpp">
</File>
<File
RelativePath="idlib\geometry\Winding.h">
</File>
<File
RelativePath="idlib\geometry\Winding2D.cpp">
</File>
<File
RelativePath="idlib\geometry\Winding2D.h">
</File>
</Filter>
<Filter
Name="Math"
Filter="">
<File
RelativePath="idlib\math\Angles.cpp">
</File>
<File
RelativePath="idlib\math\Angles.h">
</File>
<File
RelativePath=".\idlib\math\Complex.cpp">
</File>
<File
RelativePath=".\idlib\math\Complex.h">
</File>
<File
RelativePath="idlib\math\Curve.h">
</File>
<File
RelativePath="idlib\math\Extrapolate.h">
</File>
<File
RelativePath=".\idlib\math\FFT.cpp">
</File>
<File
RelativePath=".\idlib\math\FFT.h">
</File>
<File
RelativePath="idlib\math\Interpolate.h">
</File>
<File
RelativePath="idlib\math\Lcp.cpp">
</File>
<File
RelativePath="idlib\math\Lcp.h">
</File>
<File
RelativePath="idlib\math\Math.cpp">
</File>
<File
RelativePath="idlib\math\Math.h">
</File>
<File
RelativePath="idlib\math\Matrix.cpp">
</File>
<File
RelativePath="idlib\math\Matrix.h">
</File>
<File
RelativePath="idlib\math\Ode.cpp">
</File>
<File
RelativePath="idlib\math\Ode.h">
</File>
<File
RelativePath="idlib\math\Plane.cpp">
</File>
<File
RelativePath="idlib\math\Plane.h">
</File>
<File
RelativePath="idlib\math\Pluecker.cpp">
</File>
<File
RelativePath="idlib\math\Pluecker.h">
</File>
<File
RelativePath=".\idlib\math\Polynomial.cpp">
</File>
<File
RelativePath=".\idlib\math\Polynomial.h">
</File>
<File
RelativePath="idlib\math\Quat.cpp">
</File>
<File
RelativePath="idlib\math\Quat.h">
</File>
<File
RelativePath=".\idlib\math\Radians.cpp">
</File>
<File
RelativePath=".\idlib\math\Radians.h">
</File>
<File
RelativePath="idlib\math\Random.h">
</File>
<File
RelativePath="idlib\math\Rotation.cpp">
</File>
<File
RelativePath="idlib\math\Rotation.h">
</File>
<File
RelativePath="idlib\math\Simd.cpp">
</File>
<File
RelativePath="idlib\math\Simd.h">
</File>
<File
RelativePath="idlib\math\Simd_3DNow.cpp">
</File>
<File
RelativePath="idlib\math\Simd_3DNow.h">
</File>
<File
RelativePath="idlib\math\Simd_generic.cpp">
</File>
<File
RelativePath="idlib\math\Simd_Generic.h">
</File>
<File
RelativePath=".\idlib\math\Simd_InstructionMacros.h">
</File>
<File
RelativePath="idlib\math\Simd_MMX.cpp">
</File>
<File
RelativePath="idlib\math\Simd_MMX.h">
</File>
<File
RelativePath="idlib\math\Simd_SSE.cpp">
</File>
<File
RelativePath="idlib\math\Simd_SSE.h">
</File>
<File
RelativePath="idlib\math\Simd_SSE2.cpp">
</File>
<File
RelativePath="idlib\math\Simd_SSE2.h">
</File>
<File
RelativePath="idlib\math\Simd_SSE3.cpp">
</File>
<File
RelativePath="idlib\math\Simd_SSE3.h">
</File>
<File
RelativePath="idlib\math\Vector.cpp">
</File>
<File
RelativePath="idlib\math\Vector.h">
</File>
</Filter>
<Filter
Name="Hashing"
Filter="">
<File
RelativePath=".\idlib\hashing\CRC16.cpp">
</File>
<File
RelativePath=".\idlib\hashing\CRC16.h">
</File>
<File
RelativePath=".\idlib\hashing\CRC32.cpp">
</File>
<File
RelativePath=".\idlib\hashing\CRC32.h">
</File>
<File
RelativePath=".\idlib\hashing\CRC8.cpp">
</File>
<File
RelativePath=".\idlib\hashing\CRC8.h">
</File>
<File
RelativePath=".\idlib\hashing\Honeyman.cpp">
</File>
<File
RelativePath=".\idlib\hashing\Honeyman.h">
</File>
<File
RelativePath=".\idlib\hashing\MD4.cpp">
</File>
<File
RelativePath=".\idlib\hashing\MD4.h">
</File>
<File
RelativePath=".\idlib\hashing\MD5.cpp">
</File>
<File
RelativePath=".\idlib\hashing\MD5.h">
</File>
</Filter>
<Filter
Name="threads"
Filter="">
<File
RelativePath=".\idlib\threads\AutoCrit.h">
</File>
</Filter>
<Filter
Name="Algorithms"
Filter="">
<File
RelativePath=".\idlib\algorithms\MultifieldSort.h">
</File>
</Filter>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>
-117
View File
@@ -1,117 +0,0 @@
# This is the exact first-party idlib compiland set recorded in quake4.pdb.
# Additional SDK files remain in the tree for the game DLLs but are not linked
# into the reconstructed executable until evidence assigns them to the target.
set(Q4_IDLIB_SOURCES
BitMsg.cpp
CmdArgs.cpp
Dict.cpp
Heap.cpp
LangDict.cpp
Lexer.cpp
LexerFactory.cpp
Lib.cpp
mapfile.cpp
Parser.cpp
Str.cpp
Timer.cpp
Token.cpp
bv/Bounds.cpp
bv/Box.cpp
bv/Frustum.cpp
bv/Sphere.cpp
containers/HashIndex.cpp
geometry/JointTransform.cpp
geometry/Surface.cpp
geometry/Surface_Patch.cpp
geometry/TraceModel.cpp
geometry/Winding.cpp
math/Angles.cpp
math/Math.cpp
math/Matrix.cpp
math/Plane.cpp
math/Polynomial.cpp
math/Quat.cpp
math/Radians.cpp
math/Rotation.cpp
math/Simd.cpp
math/Simd_3DNow.cpp
math/Simd_generic.cpp
math/Simd_MMX.cpp
math/Simd_SSE.cpp
math/Simd_SSE2.cpp
math/Simd_SSE3.cpp
math/Vector.cpp
hashing/CRC32.cpp
hashing/MD4.cpp
hashing/MD5.cpp
)
add_library(q4_idlib STATIC ${Q4_IDLIB_SOURCES})
target_include_directories(q4_idlib
PUBLIC
${PROJECT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4_idlib
PRIVATE
WIN32
_WINDOWS
_LOAD_DLL
_USE_32BIT_TIME_T
Q4_NO_PUNKBUSTER
Q4_RECON_SEED
Q4_RECON_ENGINE_PRIVATE
Q4_RECON_SDK_MSGQUEUE
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_precompile_headers(q4_idlib PRIVATE precompiled.h)
set_target_properties(q4_idlib PROPERTIES
OUTPUT_NAME idlib
FOLDER "Engine"
)
# The Quake 4 SDK builds idlib a second time with Q4SDK for gamex86.dll.
# Several public classes (notably the SIMD hierarchy) are macro-sensitive, so
# linking the engine-private idlib into the game DLL gives the DLL a different
# vtable layout than the one seen by its game translation units.
set(Q4_GAME_IDLIB_SOURCES
${Q4_IDLIB_SOURCES}
geometry/Winding2D.cpp
math/Lcp.cpp
math/Ode.cpp
)
add_library(q4_game_idlib STATIC ${Q4_GAME_IDLIB_SOURCES})
target_include_directories(q4_game_idlib
PUBLIC
${PROJECT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}
PRIVATE
"C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
)
target_compile_definitions(q4_game_idlib
PRIVATE
WIN32
_WINDOWS
_USE_32BIT_TIME_T
Q4SDK
Q4_NO_PUNKBUSTER
$<$<CONFIG:Debug>:_DEBUG>
$<$<CONFIG:Release>:NDEBUG;_FINAL>
)
target_precompile_headers(q4_game_idlib PRIVATE precompiled.h)
set_target_properties(q4_game_idlib PROPERTIES
OUTPUT_NAME game_idlib
FOLDER "Game"
)
+1112
View File
File diff suppressed because it is too large Load Diff
+46
View File
@@ -0,0 +1,46 @@
Microsoft Visual Studio Solution File, Format Version 8.00
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Game", "game.vcproj", "{49BEC5C6-B964-417A-851E-808886B57430}"
ProjectSection(ProjectDependencies) = postProject
{49BEC5C6-B964-417A-851E-808886B57400} = {49BEC5C6-B964-417A-851E-808886B57400}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "idLib", "idlib.vcproj", "{49BEC5C6-B964-417A-851E-808886B57400}"
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MPGame", "mpgame.vcproj", "{F2EF9123-B7C3-4F2F-A351-747B595BB534}"
ProjectSection(ProjectDependencies) = postProject
{49BEC5C6-B964-417A-851E-808886B57400} = {49BEC5C6-B964-417A-851E-808886B57400}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
DebugInline = DebugInline
Release = Release
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{49BEC5C6-B964-417A-851E-808886B57430}.Debug.ActiveCfg = Debug|Win32
{49BEC5C6-B964-417A-851E-808886B57430}.Debug.Build.0 = Debug|Win32
{49BEC5C6-B964-417A-851E-808886B57430}.DebugInline.ActiveCfg = DebugInline|Win32
{49BEC5C6-B964-417A-851E-808886B57430}.DebugInline.Build.0 = DebugInline|Win32
{49BEC5C6-B964-417A-851E-808886B57430}.Release.ActiveCfg = Release|Win32
{49BEC5C6-B964-417A-851E-808886B57430}.Release.Build.0 = Release|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.Debug.ActiveCfg = Debug|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.Debug.Build.0 = Debug|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.DebugInline.ActiveCfg = DebugInline|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.DebugInline.Build.0 = DebugInline|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.Release.ActiveCfg = Release|Win32
{49BEC5C6-B964-417A-851E-808886B57400}.Release.Build.0 = Release|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.Debug.ActiveCfg = Debug|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.Debug.Build.0 = Debug|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.DebugInline.ActiveCfg = DebugInline|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.DebugInline.Build.0 = DebugInline|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.Release.ActiveCfg = Release|Win32
{F2EF9123-B7C3-4F2F-A351-747B595BB534}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
GlobalSection(ExtensibilityAddIns) = postSolution
EndGlobalSection
EndGlobal
+170
View File
@@ -0,0 +1,170 @@
// Microsoft Visual C++ generated resource script.
//
#include "common_resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"common_resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_TOOLS_OPEN DIALOGEX 0, 0, 308, 217
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP |
WS_CAPTION | WS_SYSMENU
CAPTION "Open"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
LTEXT "File &name:",IDC_STATIC,13,181,34,8
EDITTEXT IDC_TOOLS_FILENAME,51,179,187,13,ES_AUTOHSCROLL
LTEXT "Look In:",IDC_STATIC,7,9,27,8
CONTROL "",IDC_TOOLS_LOOKIN,"ComboBoxEx32",CBS_DROPDOWNLIST |
CBS_SORT | WS_VSCROLL | WS_TABSTOP,35,7,195,118
PUSHBUTTON "",IDC_TOOLS_BACK,241,7,14,13,BS_BITMAP
CONTROL "",IDC_TOOLS_FILELIST,"SysListView32",LVS_LIST |
LVS_SINGLESEL | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,
24,294,149
DEFPUSHBUTTON "&Open",IDOK,251,179,50,14
PUSHBUTTON "Cancel",IDCANCEL,251,197,50,14
END
IDD_RENDERBUMPFLAT DIALOGEX 0, 0, 186, 73
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Render Bump Flat"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
EDITTEXT IDC_RBF_WIDTH,36,6,40,14,ES_AUTOHSCROLL | ES_NUMBER
EDITTEXT IDC_RBF_HEIGHT,36,30,40,14,ES_AUTOHSCROLL | ES_NUMBER
DEFPUSHBUTTON "OK",IDOK,129,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14
LTEXT "Width:",IDC_STATIC,6,6,22,8
LTEXT "Height:",IDC_STATIC,6,30,24,8
LTEXT "File:",IDC_STATIC,6,54,14,8
LTEXT "",IDC_RBF_FILENAME,24,54,156,8
END
IDD_NEWNAME DIALOG 0, 0, 186, 46
STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "New"
FONT 8, "MS Sans Serif"
BEGIN
EDITTEXT IDC_TOOLS_EDITNAME,31,10,106,12,ES_AUTOHSCROLL
DEFPUSHBUTTON "OK",IDOK,143,7,36,14
PUSHBUTTON "Cancel",IDCANCEL,143,24,36,14
LTEXT "Name:",IDC_STATIC,7,12,22,8
END
IDD_DIALOG_GOTOLINE DIALOGEX 0, 0, 166, 54
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION |
WS_SYSMENU
CAPTION "Go To Line"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,55,33,50,14
PUSHBUTTON "Cancel",IDCANCEL,108,33,50,14
LTEXT "&Line number (0 - 0):",IDC_GOTOLINE_STATIC,7,4,152,8
EDITTEXT IDC_GOTOLINE_EDIT,7,15,152,14,ES_AUTOHSCROLL | ES_NUMBER
END
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
IDB_TOOLS_OPEN BITMAP "res\\dbg_open.bmp"
IDB_TOOLS_BACK BITMAP "res\\dbg_back.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_RENDERBUMPFLAT, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 66
END
IDD_NEWNAME, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 179
TOPMARGIN, 7
BOTTOMMARGIN, 39
END
IDD_DIALOG_GOTOLINE, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 159
TOPMARGIN, 3
BOTTOMMARGIN, 47
END
END
#endif // APSTUDIO_INVOKED
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+133
View File
@@ -0,0 +1,133 @@
// Microsoft Visual C++ generated resource script.
//
#include "proptree_resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"proptree_resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"#ifdef _WIN32\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#endif //_WIN32\r\n"
"#include ""res\\PropTree.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#endif\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Cursor
//
IDC_FPOINT CURSOR "res\\fpoint.cur"
IDC_SPLITTER CURSOR "res\\spliter.cur"
/////////////////////////////////////////////////////////////////////////////
//
// Menu
//
IDR_ME_EDIT_MENU MENU
BEGIN
POPUP "EditMenu"
BEGIN
MENUITEM "Insert File", ID_EDITMENU_INSERTFILE
MENUITEM SEPARATOR
MENUITEM "Undo", 57643
MENUITEM SEPARATOR
MENUITEM "Cut", 57635
MENUITEM "Copy", 57634
MENUITEM "Paste", 57637
MENUITEM "Delete", ID_EDIT_DELETE
MENUITEM SEPARATOR
MENUITEM "Select All", ID_EDIT_SELECTALL
END
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE
BEGIN
IDS_TRUE "True"
IDS_FALSE "False"
IDS_NOITEMSEL "No Item Selected"
IDS_SELFORINFO "Select an item to see its description"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif //_WIN32
#include "res\PropTree.rc2" // non-Microsoft Visual C++ edited resources
// MFC standard resources are already linked by the DLL target. Including
// afxres.rc here duplicates its string-table blocks when this resource script
// is combined with Radiant.rc.
#endif
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
+6
View File
@@ -0,0 +1,6 @@
#include "doom_resource.h"
// Visual resources recovered from the matching retail quake4.exe. Keep the
// original numeric identifiers because the Win32 code loads them directly.
IDI_ICON1 ICON "retail\\quake4\\icons\\1024_1033.ico"
IDB_BITMAP_LOGO BITMAP "retail\\quake4\\bitmaps\\4001_1033.bmp"
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

+19
View File
@@ -0,0 +1,19 @@
<HTML>
<BODY ID=CGetString BGCOLOR=LIGHTGREY>
<TABLE WIDTH=100%>
<TR>
<TD ALIGN=RIGHT>
<BUTTON STYLE="WIDTH:100" ID="ButtonOK">OK</BUTTON><BR>
<BUTTON STYLE="WIDTH:100" ID="ButtonCancel">Cancel</BUTTON>
</TD>
</TR>
<TR WIDTH=100% HEIGHT=75>
<TD ALIGN=CENTER VALIGN=BOTTOM>
TODO: Place controls here.
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

+13
View File
@@ -0,0 +1,13 @@
//
// PROPTREE.RC2 - resources Microsoft Visual C++ does not edit directly
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...
/////////////////////////////////////////////////////////////////////////////
Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@@ -0,0 +1,27 @@
{
"source": "E:\\projects\\Quake4Alpha\\quake4.exe",
"source_size": 4919296,
"source_sha256": "3b713ad6114ae9a8427bc23c7317c736d86c67419eb8a1e275c9591aaf7be6ea",
"resource_directory_rva": "0x013b5000",
"resource_directory_size": 613584,
"emitted": [
{
"resource_type": "2",
"resource_name": "4001",
"language": "1033",
"rva": "0x013ba9f0",
"path": "bitmaps/4001_1033.bmp",
"size": 589880,
"sha256": "bef78ce90873fdad6eaa8030056a5cc9d9b6e4a4973c44e893109bd183745ce1"
},
{
"resource_type": "14",
"resource_name": "1024",
"language": "1033",
"rva": "0x013ba990",
"path": "icons/1024_1033.ico",
"size": 22486,
"sha256": "0d6c0d7b3293db959c4268743b6fabc05b7b242438641acd005a15f079c96a37"
}
]
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

Some files were not shown because too many files have changed in this diff Show More