Added miss
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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__ */
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
)
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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"
|
||||
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 614 B |
|
After Width: | Height: | Size: 614 B |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 486 B |
@@ -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>
|
||||
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 486 B |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 766 B |
@@ -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...
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 718 B |
|
After Width: | Height: | Size: 614 B |
|
After Width: | Height: | Size: 614 B |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 1014 B |
|
After Width: | Height: | Size: 502 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 119 KiB |
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 310 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 502 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 766 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1014 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 766 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 318 B |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 326 B |
|
After Width: | Height: | Size: 576 KiB |
|
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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 502 B |
|
After Width: | Height: | Size: 310 B |
|
After Width: | Height: | Size: 1014 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 198 B |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 486 B |