mirror of
https://github.com/id-Software/DOOM-3-BFG.git
synced 2025-03-13 22:22:05 +00:00
Added Imgui AF editor by Stephen Pridham
This commit is contained in:
parent
f4e84b50db
commit
25b7680cfb
15 changed files with 2164 additions and 18 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -35,6 +35,7 @@ base/sound/
|
|||
base/strings/
|
||||
base/video/
|
||||
base/wads/
|
||||
base/renderprogs2/
|
||||
|
||||
GPATH
|
||||
GRTAGS
|
||||
|
|
|
@ -69,7 +69,9 @@ option(USE_DX12
|
|||
"Use DirectX 12" ON)
|
||||
|
||||
option(USE_NVRHI_VULKAN
|
||||
"Use Vulkan" OFF)
|
||||
"Use Vulkan" ON)
|
||||
|
||||
set(NVRHI_INSTALL OFF)
|
||||
|
||||
set(CPU_TYPE "" CACHE STRING "When set, passes this string as CPU-ID which will be embedded into the binary.")
|
||||
|
||||
|
@ -203,7 +205,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
|
|||
add_compile_options(-fno-strict-aliasing)
|
||||
|
||||
# SRS - Make sure OSX can find system headers and add support for minimum OSX runtime version
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if(APPLE)
|
||||
# SRS - Also add -fasm-blocks otherwise Xcode complains and -Qunused-arguments to silence MMX/SSE unused arg warnings when compiling for Apple arm64
|
||||
add_definitions(-fasm-blocks -Qunused-arguments)
|
||||
if(CMAKE_OSX_SYSROOT)
|
||||
|
@ -368,7 +370,7 @@ if(USE_VULKAN)
|
|||
# which causes all kinds of weird segmentation faults because struct sizes don't match
|
||||
|
||||
# SRS - Set default VULKAN_SDK location if environment variable not defined on OSX
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT DEFINED ENV{VULKAN_SDK})
|
||||
if(APPLE AND NOT DEFINED ENV{VULKAN_SDK})
|
||||
if(NOT USE_MoltenVK)
|
||||
# SRS - Vulkan SDK installer copies standard vulkan headers and libs to /usr/local on OSX
|
||||
set(ENV{VULKAN_SDK} /usr/local)
|
||||
|
@ -425,7 +427,7 @@ if(USE_VULKAN)
|
|||
add_definitions(-DUSE_VULKAN)
|
||||
include_directories($ENV{VULKAN_SDK}/include)
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if(APPLE)
|
||||
# SRS - Enable Beta extensions for VULKAN_SDK portability subset features on OSX
|
||||
add_definitions(-DVK_ENABLE_BETA_EXTENSIONS)
|
||||
# SRS - Optionally use MoltenVK headers/library for runtime config functions on OSX
|
||||
|
@ -450,7 +452,7 @@ elseif(USE_NVRHI_VULKAN)
|
|||
# which causes all kinds of weird segmentation faults because struct sizes don't match
|
||||
|
||||
# SRS - Set default VULKAN_SDK location if environment variable not defined on OSX
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT DEFINED ENV{VULKAN_SDK})
|
||||
if(APPLE AND NOT DEFINED ENV{VULKAN_SDK})
|
||||
if(NOT USE_MoltenVK)
|
||||
# SRS - Vulkan SDK installer copies standard vulkan headers and libs to /usr/local on OSX
|
||||
set(ENV{VULKAN_SDK} /usr/local)
|
||||
|
@ -465,6 +467,37 @@ elseif(USE_NVRHI_VULKAN)
|
|||
find_package(Vulkan)
|
||||
endif()
|
||||
|
||||
if(NOT Vulkan_FOUND)
|
||||
message(FATAL_ERROR "Could not find Vulkan library!")
|
||||
else()
|
||||
include_directories($ENV{VULKAN_SDK}/include)
|
||||
|
||||
if(APPLE)
|
||||
# SRS - Enable Beta extensions for VULKAN_SDK portability subset features on OSX
|
||||
add_definitions(-DVK_ENABLE_BETA_EXTENSIONS)
|
||||
# SRS - Optionally use MoltenVK headers/library for runtime config functions on OSX
|
||||
if(USE_MoltenVK)
|
||||
add_definitions(-DUSE_MoltenVK)
|
||||
include_directories($ENV{VULKAN_SDK}/../MoltenVK/include)
|
||||
set(Vulkan_LIBRARY $ENV{VULKAN_SDK}/../MoltenVK/dylib/macOS/libMoltenVK.dylib CACHE FILEPATH "Path to MoltenVK library." FORCE)
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using Vulkan: " ${Vulkan_LIBRARY})
|
||||
endif()
|
||||
|
||||
# Eric: For use with SDL2/Vulkan
|
||||
if(UNIX)
|
||||
# SRS - For UNIX-like target OSs use the generic SDL Vulkan platform
|
||||
add_definitions(-DUSE_NVRHI_SDL)
|
||||
elseif(WIN32)
|
||||
add_definitions(-DVK_USE_PLATFORM_WIN32_KHR)
|
||||
endif()
|
||||
# Use FindVulkan module added with CMAKE 3.7
|
||||
if(NOT CMAKE_VERSION VERSION_LESS 3.7.0)
|
||||
message( STATUS "Using module to find Vulkan" )
|
||||
find_package(Vulkan)
|
||||
endif()
|
||||
|
||||
if(NOT Vulkan_FOUND)
|
||||
message(FATAL_ERROR "Could not find Vulkan library!")
|
||||
else()
|
||||
|
@ -1172,7 +1205,7 @@ file(GLOB SDL_SOURCES sys/sdl/*.cpp)
|
|||
|
||||
# Eric: Utilize either the Vulkan or GL implementation of SDL
|
||||
if(UNIX)
|
||||
if(USE_VULKAN)
|
||||
if(USE_VULKAN OR USE_NVRHI)
|
||||
get_filename_component(sdl_glimp_cpp_full_path ${CMAKE_CURRENT_SOURCE_DIR}/sys/sdl/sdl_glimp.cpp ABSOLUTE)
|
||||
list(REMOVE_ITEM SDL_SOURCES "${sdl_glimp_cpp_full_path}")
|
||||
else()
|
||||
|
@ -1520,6 +1553,19 @@ set(RBDOOM3_SOURCES
|
|||
${GAMED3XP_SCRIPT_SOURCES}
|
||||
)
|
||||
|
||||
macro(AddSubdirectory dirName)
|
||||
file(GLOB DIR_INCLUDES ${dirName}/*.h)
|
||||
file(GLOB DIR_SOURCES ${dirName}/*.cpp)
|
||||
|
||||
source_group(${dirName} FILES ${DIR_INCLUDES})
|
||||
source_group(${dirName} FILES ${DIR_SOURCES})
|
||||
|
||||
list(APPEND RBDOOM3_INCLUDES ${DIR_INCLUDES})
|
||||
list(APPEND RBDOOM3_SOURCES ${DIR_SOURCES})
|
||||
endmacro()
|
||||
|
||||
AddSubdirectory( tools/imgui/afeditor )
|
||||
|
||||
if(DOOM_CLASSIC)
|
||||
add_definitions(-DUSE_DOOMCLASSIC)
|
||||
|
||||
|
@ -1782,7 +1828,7 @@ else()
|
|||
set(SDLx_LIBRARY ${SDL_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
if(APPLE)
|
||||
list(REMOVE_ITEM POSIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sys/posix/platform_linux.cpp)
|
||||
else()
|
||||
list(REMOVE_ITEM POSIX_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/sys/posix/platform_osx.cpp)
|
||||
|
@ -1797,7 +1843,7 @@ else()
|
|||
add_definitions(-DUSE_OPENAL)
|
||||
|
||||
# SRS - Added support for OpenAL Soft headers on OSX (vs default macOS SDK headers)
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT OPENAL_INCLUDE_DIR MATCHES "SDKs/MacOSX.*\.sdk")
|
||||
if(APPLE AND NOT OPENAL_INCLUDE_DIR MATCHES "SDKs/MacOSX.*\.sdk")
|
||||
include_directories(${OPENAL_INCLUDE_DIR})
|
||||
add_definitions(-DUSE_OPENAL_SOFT_INCLUDES)
|
||||
endif()
|
||||
|
@ -1834,7 +1880,13 @@ else()
|
|||
list(APPEND Vulkan_LIBRARIES glslang-default-resource-limits)
|
||||
endif()
|
||||
endif()
|
||||
elseif(USE_NVRHI)
|
||||
list(APPEND RBDOOM3_INCLUDES ${RENDERER_NVRHI_INCLUDES})
|
||||
list(APPEND RBDOOM3_SOURCES ${RENDERER_NVRHI_SOURCES})
|
||||
|
||||
set(OpenGL_LIBRARIES
|
||||
opengl32
|
||||
glu32)
|
||||
else()
|
||||
find_package(OpenGL REQUIRED)
|
||||
include_directories(${OPENGL_INCLUDE_DIRS})
|
||||
|
@ -1915,6 +1967,9 @@ else()
|
|||
|
||||
add_executable(RBDoom3BFG WIN32 ${RBDOOM3_SOURCES})
|
||||
|
||||
if(USE_NVRHI_VULKAN)
|
||||
add_dependencies(RBDoom3BFG nvrhi_vk)
|
||||
endif()
|
||||
if (USE_PRECOMPILED_HEADERS)
|
||||
# make sure precompiled header is created before executable is compiled
|
||||
add_dependencies(RBDoom3BFG precomp_header_rbdoom3bfg)
|
||||
|
@ -1924,7 +1979,7 @@ else()
|
|||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
if(NOT "${CMAKE_SYSTEM}" MATCHES "Darwin")
|
||||
if(NOT APPLE)
|
||||
set(RT_LIBRARY rt)
|
||||
endif()
|
||||
|
||||
|
@ -1946,12 +2001,6 @@ else()
|
|||
endif()
|
||||
endif()
|
||||
|
||||
if(USE_DX11)
|
||||
#target_sources(RBDoom3BFG PRIVATE src/app/dx11/DeviceManager_DX11.cpp)
|
||||
target_compile_definitions(RBDoom3BFG PUBLIC USE_DX11=1)
|
||||
target_link_libraries(RBDoom3BFG nvrhi_d3d11)
|
||||
endif()
|
||||
|
||||
if(USE_DX12)
|
||||
target_compile_definitions(RBDoom3BFG PUBLIC USE_DX12=1)
|
||||
target_link_libraries(RBDoom3BFG nvrhi_d3d12)
|
||||
|
|
|
@ -31,7 +31,7 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
// *INDENT-OFF*
|
||||
#if USE_GPU_SKINNING
|
||||
StructuredBuffer<float4> matrices : register(t11);
|
||||
StructuredBuffer<float4> matrices : register( t11 );
|
||||
#endif
|
||||
|
||||
struct VS_IN
|
||||
|
|
|
@ -31,8 +31,8 @@ If you have questions concerning this license or the applicable additional terms
|
|||
|
||||
|
||||
// *INDENT-OFF*
|
||||
Texture2D t_CurrentRender : register( t0 VK_DESCRIPTOR_SET( 0 ) );
|
||||
Texture2D t_HeatMap : register( t1 VK_DESCRIPTOR_SET( 0 ) );
|
||||
Texture2D t_CurrentRender : register( t0 VK_DESCRIPTOR_SET( 0 ) );
|
||||
Texture2D t_HeatMap : register( t1 VK_DESCRIPTOR_SET( 0 ) );
|
||||
|
||||
SamplerState samp0 : register( s0 VK_DESCRIPTOR_SET( 1 ) ); // texture 0 is _currentRender
|
||||
SamplerState samp1 : register( s1 VK_DESCRIPTOR_SET( 1 ) ); // texture 1 is heatmap
|
||||
|
|
|
@ -157,6 +157,8 @@ void DrawToolWindows();
|
|||
|
||||
void LightEditorInit( const idDict* dict, idEntity* entity );
|
||||
|
||||
void AfEditorInit();
|
||||
|
||||
}
|
||||
|
||||
#endif /* !__EDIT_PUBLIC_H__ */
|
||||
|
|
356
neo/tools/imgui/afeditor/AfBodyEditor.cpp
Normal file
356
neo/tools/imgui/afeditor/AfBodyEditor.cpp
Normal file
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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 "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AfBodyEditor.h"
|
||||
|
||||
#include "../imgui/BFGimgui.h"
|
||||
|
||||
static const char* bodyTypeNames[] =
|
||||
{
|
||||
"none",
|
||||
"box",
|
||||
"octahedron",
|
||||
"dedecahedron",
|
||||
"cylinder",
|
||||
"cone",
|
||||
"bone",
|
||||
"polygon",
|
||||
"polygonvolume",
|
||||
"custom"
|
||||
};
|
||||
|
||||
static const char* modifyJointsNames[] =
|
||||
{
|
||||
"axis",
|
||||
"origin",
|
||||
"both"
|
||||
};
|
||||
|
||||
static const char* afVecTypeNames[] =
|
||||
{
|
||||
"coordinates",
|
||||
"joint",
|
||||
"bone center",
|
||||
};
|
||||
|
||||
static bool ModelTypeItemGetter( void* data, int index, const char** out );
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
AfBodyEditor::AfBodyEditor( idDeclAF* newDecl, idDeclAF_Body* newBody )
|
||||
: decl( newDecl )
|
||||
, body( newBody )
|
||||
, positionType( 0 )
|
||||
, modifyJointType( 0 )
|
||||
, comboJoint1( 0 )
|
||||
, comboJoint2( 0 )
|
||||
, originBoneCenterJoint1( 0 )
|
||||
, originBoneCenterJoint2( 0 )
|
||||
, originJoint( 0 )
|
||||
, contentWidget( MakePhysicsContentsSelector() )
|
||||
{
|
||||
InitJointLists();
|
||||
}
|
||||
|
||||
AfBodyEditor::~AfBodyEditor()
|
||||
{
|
||||
}
|
||||
|
||||
bool AfBodyEditor::Do()
|
||||
{
|
||||
ImGui::PushID( body->name );
|
||||
|
||||
bool changed = false;
|
||||
|
||||
ImGui::InputText( "##rename", &renameBody );
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( "Rename" ) )
|
||||
{
|
||||
if( renameBody.Allocated() > 0 )
|
||||
{
|
||||
decl->RenameBody( body->name, renameBody.c_str() );
|
||||
renameBody.Clear();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Collision Model" ) )
|
||||
{
|
||||
changed = CollisionModel() || changed;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Position" ) )
|
||||
{
|
||||
changed = Position() || changed;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Collision Detection" ) )
|
||||
{
|
||||
changed = ImGui::Checkbox( "Self Collision", &body->selfCollision ) || changed;
|
||||
changed = DoMultiSelect( &contentWidget, &body->contents ) || changed;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Friction" ) )
|
||||
{
|
||||
changed = ImGui::DragFloat( "Linear", &body->linearFriction ) || changed;
|
||||
changed = ImGui::DragFloat( "Angular", &body->angularFriction ) || changed;
|
||||
changed = ImGui::DragFloat( "Contact", &body->contactFriction ) || changed;
|
||||
changed = InputAfVector( "Friction Direction", &body->frictionDirection ) || changed;
|
||||
changed = InputAfVector( "Motor Direction", &body->contactMotorDirection ) || changed;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Joints" ) )
|
||||
{
|
||||
if( ImGui::Combo( "Modified Joint", &comboJoint1, StringListItemGetter, &joints, joints.Num() ) )
|
||||
{
|
||||
body->jointName = joints[comboJoint1];
|
||||
changed = true;
|
||||
}
|
||||
changed = ImGui::Combo( "Modify", ( int* )&body->jointMod, modifyJointsNames, ARRAY_COUNT( modifyJointsNames ) ) || changed;
|
||||
changed = ImGui::InputText( "Contained Joints", &body->containedJoints ) || changed;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void AfBodyEditor::InitJointLists()
|
||||
{
|
||||
const idRenderModel* model = gameEdit->ANIM_GetModelFromName( decl->model.c_str() );
|
||||
if( !model )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const int numJoints = model->NumJoints();
|
||||
for( int i = 0; i < numJoints; i++ )
|
||||
{
|
||||
const char* jointName = model->GetJointName( ( jointHandle_t )i );
|
||||
joints[joints.Append( jointName )].ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
bool AfBodyEditor::Position()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
ImGui::Columns( 2, "positionColumns2" );
|
||||
|
||||
changed = ImGui::Combo( "Type", ( int* )&body->origin.type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
|
||||
ImGui::NextColumn();
|
||||
changed = PositionProperty() || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = PitchYawRoll() || changed;
|
||||
|
||||
ImGui::Columns( 1 );
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfBodyEditor::PositionProperty()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
idAFVector* afVec = &body->origin;
|
||||
|
||||
switch( afVec->type )
|
||||
{
|
||||
case idAFVector::VEC_COORDS:
|
||||
changed = ImGui::DragFloat3( "Coordinates", ( float* )&afVec->ToVec3() ) || changed;
|
||||
break;
|
||||
case idAFVector::VEC_JOINT:
|
||||
if( ImGui::BeginCombo( "Joint", afVec->joint1.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint1 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
changed = true;
|
||||
afVec->joint1 = joints[n];
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
break;
|
||||
case idAFVector::VEC_BONECENTER:
|
||||
case idAFVector::VEC_BONEDIR:
|
||||
if( ImGui::BeginCombo( "Joint 1", afVec->joint1.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint1 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
changed = true;
|
||||
afVec->joint1 = joints[n];
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if( ImGui::BeginCombo( "Joint 2", afVec->joint2.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint2 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
changed = true;
|
||||
afVec->joint2 = joints[n];
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ImGui::Text( "*Unknown Type*" );
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfBodyEditor::PitchYawRoll()
|
||||
{
|
||||
bool changed = false;
|
||||
const ImGuiStyle& style = ImGui::GetStyle();
|
||||
const float w_full = ImGui::CalcItemWidth();
|
||||
const float square_sz = ImGui::GetFrameHeight();
|
||||
const float w_button = square_sz + style.ItemInnerSpacing.x;
|
||||
const float w_inputs = w_full - w_button;
|
||||
|
||||
const float widthItemOne = Max( 1.0f, ( float )( int )( ( w_inputs - ( style.ItemInnerSpacing.x ) * 2 ) / 2.0f ) );
|
||||
const float widthItemLast = Max( 1.0f, ( float )( int )( w_inputs - ( widthItemOne + style.ItemInnerSpacing.x ) ) );
|
||||
|
||||
ImGui::SetNextItemWidth( widthItemOne );
|
||||
changed = ImGui::DragFloat( "##p", &body->angles.pitch, 1.0f, 0.0f, 360.0f, "pitch: %.3f" ) || changed;
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth( widthItemOne );
|
||||
changed = ImGui::DragFloat( "##y", &body->angles.yaw, 1.0f, 0.0f, 360.0f, "yaw: %.3f" ) || changed;
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth( widthItemLast );
|
||||
changed = ImGui::DragFloat( "##r", &body->angles.roll, 1.0f, 0.0f, 360.0f, "roll: %.3f" );
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfBodyEditor::CollisionModel()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
ImGui::PushID( "CollisionModel" );
|
||||
|
||||
ImGui::Columns( 2, "collisonColumns2" );
|
||||
changed = ImGui::Combo( "Model Type", &body->modelType, ModelTypeItemGetter, nullptr, ARRAY_COUNT( bodyTypeNames ) ) || changed;
|
||||
changed = ImGui::DragFloat( "Density", &body->density ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = CollisionModelSize() || changed;
|
||||
ImGui::Columns( 1 );
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfBodyEditor::CollisionModelSize()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
switch( body->modelType )
|
||||
{
|
||||
case TRM_INVALID:
|
||||
ImGui::Text( "Provide a valid model type." );
|
||||
break;
|
||||
case TRM_BOX:
|
||||
case TRM_OCTAHEDRON:
|
||||
case TRM_DODECAHEDRON:
|
||||
changed = InputAfVector( "min", &body->v1 ) || changed;
|
||||
changed = InputAfVector( "max", &body->v2 ) || changed;
|
||||
ImGui::NewLine();
|
||||
break;
|
||||
case TRM_CYLINDER:
|
||||
case TRM_CONE:
|
||||
changed = InputAfVector( "min", &body->v1 ) || changed;
|
||||
changed = InputAfVector( "max", &body->v2 ) || changed;
|
||||
changed = ImGui::InputInt( "Sides", &body->numSides ) || changed;
|
||||
break;
|
||||
case TRM_BONE:
|
||||
changed = InputAfVector( "min", &body->v1 ) || changed;
|
||||
changed = InputAfVector( "max", &body->v2 ) || changed;
|
||||
changed = ImGui::DragFloat( "Width", &body->width ) || changed;
|
||||
break;
|
||||
case TRM_POLYGON:
|
||||
ImGui::TextColored( ImVec4( 1, 0, 0, 1 ), "Polygon models are not supported :(" );
|
||||
break;
|
||||
case TRM_POLYGONVOLUME:
|
||||
ImGui::TextColored( ImVec4( 1, 0, 0, 1 ), "Polygon Volume models are not supported :(" );
|
||||
break;
|
||||
case TRM_CUSTOM:
|
||||
ImGui::TextColored( ImVec4( 1, 0, 0, 1 ), "Custom models are not supported :(" );
|
||||
break;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfBodyEditor::InputAfVector( const char* label, idAFVector* vec )
|
||||
{
|
||||
return ImGui::DragFloat3( label, ( float* )&vec->ToVec3() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static bool ModelTypeItemGetter( void* data, int index, const char** out )
|
||||
{
|
||||
if( index < 0 || index >= ARRAY_COUNT( bodyTypeNames ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = bodyTypeNames[index];
|
||||
|
||||
return true;
|
||||
}
|
72
neo/tools/imgui/afeditor/AfBodyEditor.h
Normal file
72
neo/tools/imgui/afeditor/AfBodyEditor.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../util/Imgui_IdWidgets.h"
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
class AfBodyEditor
|
||||
{
|
||||
public:
|
||||
AfBodyEditor( idDeclAF* newDecl, idDeclAF_Body* newBody );
|
||||
~AfBodyEditor();
|
||||
|
||||
bool Do();
|
||||
|
||||
private:
|
||||
|
||||
void InitJointLists();
|
||||
|
||||
bool Position();
|
||||
bool PositionProperty();
|
||||
bool PitchYawRoll();
|
||||
bool CollisionModel();
|
||||
bool CollisionModelSize();
|
||||
bool InputAfVector( const char* label, idAFVector* vec );
|
||||
|
||||
idDeclAF* decl;
|
||||
idDeclAF_Body* body;
|
||||
int positionType;
|
||||
int modifyJointType;
|
||||
int comboJoint1;
|
||||
int comboJoint2;
|
||||
int originBoneCenterJoint1;
|
||||
int originBoneCenterJoint2;
|
||||
int originJoint;
|
||||
MultiSelectWidget contentWidget;
|
||||
|
||||
idStr modifiedJoint;
|
||||
idStr renameBody;
|
||||
idStrList joints;
|
||||
};
|
||||
|
||||
}
|
409
neo/tools/imgui/afeditor/AfConstraintEditor.cpp
Normal file
409
neo/tools/imgui/afeditor/AfConstraintEditor.cpp
Normal file
|
@ -0,0 +1,409 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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 "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AfConstraintEditor.h"
|
||||
|
||||
#include "../imgui/BFGimgui.h"
|
||||
|
||||
static const char* constraintTypeNames[] =
|
||||
{
|
||||
"Invalid",
|
||||
"Fixed",
|
||||
"Ball and Socket Joint",
|
||||
"Universal Joint",
|
||||
"Hinge",
|
||||
"Slider",
|
||||
"Spring"
|
||||
};
|
||||
|
||||
static const char* anchorTypeNames[] =
|
||||
{
|
||||
"joint",
|
||||
"coorindates"
|
||||
};
|
||||
|
||||
static const char* jointPointTypeNames[] =
|
||||
{
|
||||
"bone",
|
||||
"angles"
|
||||
};
|
||||
|
||||
static const char* afVecTypeNames[] =
|
||||
{
|
||||
"coordinates",
|
||||
"joint",
|
||||
"bone center",
|
||||
"bone direction"
|
||||
};
|
||||
|
||||
static const char* constraintLimitTypeNames[] =
|
||||
{
|
||||
"none",
|
||||
"cone",
|
||||
"pyramid"
|
||||
};
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
static bool BodyItemGetter( void* data, int index, const char** out );
|
||||
static bool ConstraintLimitTypeGetter( void* data, int index, const char** out );
|
||||
|
||||
AfConstraintEditor::AfConstraintEditor( idDeclAF* newDecl, idDeclAF_Constraint* newConstraint )
|
||||
: decl( newDecl )
|
||||
, constraint( newConstraint )
|
||||
, anchorType( 0 )
|
||||
, shaft1Type( 0 )
|
||||
, shaft2Type( 0 )
|
||||
, limitOrientationType( 0 )
|
||||
, body1( 0 )
|
||||
, body2( 0 )
|
||||
, jointAnchor1( 0 )
|
||||
, jointAnchor2( 0 )
|
||||
, jointShaft1( 0 )
|
||||
{
|
||||
InitJointLists();
|
||||
}
|
||||
|
||||
AfConstraintEditor::~AfConstraintEditor()
|
||||
{
|
||||
}
|
||||
|
||||
bool AfConstraintEditor::Do()
|
||||
{
|
||||
ImGui::PushID( constraint->name.c_str() );
|
||||
|
||||
bool changed = false;
|
||||
|
||||
ImGui::InputText( "##rename", &renameConstraint );
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "Rename" ) )
|
||||
{
|
||||
if( renameConstraint.Allocated() > 0 )
|
||||
{
|
||||
decl->RenameConstraint( constraint->name, renameConstraint.c_str() );
|
||||
renameConstraint.Clear();
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "General" ) )
|
||||
{
|
||||
ImGui::Columns( 2, "constraintGeneral2" );
|
||||
changed = ImGui::Combo( "Type##General", ( int* )&constraint->type, constraintTypeNames, ARRAY_COUNT( constraintTypeNames ) ) || changed;
|
||||
changed = ImGui::DragFloat( "Friction##Friction", &constraint->friction ) || changed;
|
||||
|
||||
if( constraint->type == DECLAF_CONSTRAINT_SPRING )
|
||||
{
|
||||
changed = ImGui::DragFloat( "Stretch", &constraint->stretch ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Spring constant when the spring is stretched" );
|
||||
changed = ImGui::DragFloat( "Compress", &constraint->compress, 0.001f, 0.0f, 1.0f ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Spring constant when the spring is compressed" );
|
||||
changed = ImGui::DragFloat( "Damping", &constraint->damping, 0.001f, 0.0f, 1.0f ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Spring damping" );
|
||||
changed = ImGui::DragFloat( "Length", &constraint->restLength, 0.001f, 0.0f, 1.0f ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Rest length of the spring" );
|
||||
changed = ImGui::DragFloat( "Min Length", &constraint->minLength, 0.001f, 0.0f, 1.0f ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Minimum length of the spring" );
|
||||
changed = ImGui::DragFloat( "Max Length", &constraint->maxLength, 0.001f, 0.0f, 1.0f ) || changed;
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Maximum length of the spring" );
|
||||
}
|
||||
|
||||
ImGui::NextColumn();
|
||||
if( ImGui::BeginCombo( "Body 1", constraint->body1.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < decl->bodies.Num(); n++ )
|
||||
{
|
||||
bool isSelected = ( constraint->body1 == decl->bodies[n]->name );
|
||||
if( ImGui::Selectable( decl->bodies[n]->name, isSelected ) )
|
||||
{
|
||||
constraint->body1 = decl->bodies[n]->name;
|
||||
changed = true;
|
||||
}
|
||||
if( isSelected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if( ImGui::BeginCombo( "Body 2", constraint->body2.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < decl->bodies.Num(); n++ )
|
||||
{
|
||||
bool isSelected = ( constraint->body2 == decl->bodies[n]->name );
|
||||
if( ImGui::Selectable( decl->bodies[n]->name, isSelected ) )
|
||||
{
|
||||
constraint->body2 = decl->bodies[n]->name;
|
||||
changed = true;
|
||||
}
|
||||
if( isSelected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::Columns( 1 );
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Anchor" ) )
|
||||
{
|
||||
ImGui::PushID( "Anchor1" );
|
||||
ImGui::Columns( 2, "anchorColumn2" );
|
||||
changed = ImGui::Combo( "Type##anchor", ( int* )&constraint->anchor.type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = InputAfVector( &constraint->anchor ) || changed;
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if( constraint->type == DECLAF_CONSTRAINT_SPRING )
|
||||
{
|
||||
if( ImGui::CollapsingHeader( "Anchor2" ) )
|
||||
{
|
||||
ImGui::PushID( "Anchor2" );
|
||||
ImGui::Columns( 2, "anchorColumn2" );
|
||||
changed = ImGui::Combo( "Type##anchor", ( int* )&constraint->anchor2.type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = InputAfVector( &constraint->anchor2 ) || changed;
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
if( constraint->type == DECLAF_CONSTRAINT_UNIVERSALJOINT )
|
||||
{
|
||||
if( ImGui::CollapsingHeader( "Shaft 1" ) )
|
||||
{
|
||||
ImGui::PushID( "Shaft 1" );
|
||||
ImGui::Columns( 2, "shaft12" );
|
||||
changed = ImGui::Combo( "Type", ( int* )&constraint->shaft[0].type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = InputAfVector( &constraint->shaft[0] ) || changed;
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Shaft 2" ) )
|
||||
{
|
||||
ImGui::PushID( "Shaft 2" );
|
||||
ImGui::Columns( 2, "shaft22" );
|
||||
changed = ImGui::Combo( "Type", ( int* )&constraint->shaft[1].type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = InputAfVector( &constraint->shaft[1] ) || changed;
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
if( constraint->type == DECLAF_CONSTRAINT_HINGE )
|
||||
{
|
||||
if( ImGui::CollapsingHeader( "Limit Orientation" ) )
|
||||
{
|
||||
ImGui::DragFloat3( "Limit Angles", &constraint->limitAngles[0] );
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "Specifies a V-shaped limit."
|
||||
"\nThe first angle specifies the center of the V-shaped limit."
|
||||
"\nThe angle which specifies the width of the V-shaped limit follows."
|
||||
"\nThe V-shape is attached to body2. Next a shaft is specified which"
|
||||
"\nis attached to body1 and is constrained to always stay within the V-shape."
|
||||
"\nThe orientation of this shaft is specified with the third angle." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ImGui::CollapsingHeader( "Limit Type" ) )
|
||||
{
|
||||
ImGui::PushID( "LimitType" );
|
||||
ImGui::Columns( 2, "limit2" );
|
||||
changed = ImGui::Combo( "Type", ( int* )&constraint->limit, ConstraintLimitTypeGetter, nullptr, ARRAY_COUNT( constraintLimitTypeNames ) - 1 ) || changed;
|
||||
ImGui::NextColumn();
|
||||
switch( constraint->limit )
|
||||
{
|
||||
case idDeclAF_Constraint::LIMIT_NONE:
|
||||
break;
|
||||
case idDeclAF_Constraint::LIMIT_CONE:
|
||||
changed = ImGui::DragFloat3( "Cone##Limit", ( float* )&constraint->limitAngles[0], 0, -359.0f, 360.0f ) || changed;
|
||||
break;
|
||||
case idDeclAF_Constraint::LIMIT_PYRAMID:
|
||||
changed = ImGui::DragFloat3( "Pyramid##Limit", ( float* )&constraint->limitAngles[0], 0, -359.0f, 360.0f ) || changed;
|
||||
break;
|
||||
}
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Limit Orientation" ) )
|
||||
{
|
||||
ImGui::PushID( "LimitO" );
|
||||
ImGui::Columns( 2, "limitOrientation2" );
|
||||
changed = ImGui::Combo( "Type", ( int* )&constraint->limitAxis.type, afVecTypeNames, ARRAY_COUNT( afVecTypeNames ) ) || changed;
|
||||
ImGui::NextColumn();
|
||||
changed = InputAfVector( &constraint->limitAxis ) || changed;
|
||||
ImGui::Columns( 1 );
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool AfConstraintEditor::InputAfVector( idAFVector* afVec )
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
switch( afVec->type )
|
||||
{
|
||||
case idAFVector::VEC_COORDS:
|
||||
changed = changed || ImGui::DragFloat3( "Coordinates", ( float* )&afVec->ToVec3() );
|
||||
break;
|
||||
case idAFVector::VEC_JOINT:
|
||||
if( ImGui::BeginCombo( "Joint", afVec->joint1.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint1 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
afVec->joint1 = joints[n];
|
||||
changed = true;
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
break;
|
||||
case idAFVector::VEC_BONECENTER:
|
||||
case idAFVector::VEC_BONEDIR:
|
||||
if( ImGui::BeginCombo( "Joint 1", afVec->joint1.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint1 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
afVec->joint1 = joints[n];
|
||||
changed = true;
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
if( ImGui::BeginCombo( "Joint 2", afVec->joint2.c_str() ) )
|
||||
{
|
||||
for( int n = 0; n < joints.Num(); n++ )
|
||||
{
|
||||
bool is_selected = ( afVec->joint2 == joints[n] );
|
||||
if( ImGui::Selectable( joints[n], is_selected ) )
|
||||
{
|
||||
afVec->joint2 = joints[n];
|
||||
changed = true;
|
||||
}
|
||||
if( is_selected )
|
||||
{
|
||||
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ImGui::Text( "*Unknown Type*" );
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void AfConstraintEditor::InitJointLists()
|
||||
{
|
||||
const idRenderModel* model = gameEdit->ANIM_GetModelFromName( decl->model.c_str() );
|
||||
if( !model )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
joints.Clear();
|
||||
|
||||
const int numJoints = model->NumJoints();
|
||||
for( int i = 0; i < numJoints; i++ )
|
||||
{
|
||||
const char* jointName = model->GetJointName( ( jointHandle_t )i );
|
||||
joints[joints.Append( jointName )].ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
static bool BodyItemGetter( void* data, int index, const char** out )
|
||||
{
|
||||
idDeclAF* decl = reinterpret_cast<idDeclAF*>( data );
|
||||
if( index < 0 || index >= decl->bodies.Num() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
idDeclAF_Body* body = decl->bodies[index];
|
||||
*out = body->name.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConstraintLimitTypeGetter( void* data, int index, const char** out )
|
||||
{
|
||||
index += 1;
|
||||
|
||||
if( index < 0 || index > ARRAY_COUNT( constraintLimitTypeNames ) )
|
||||
{
|
||||
*out = constraintLimitTypeNames[0];
|
||||
return false;
|
||||
}
|
||||
|
||||
*out = constraintLimitTypeNames[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
65
neo/tools/imgui/afeditor/AfConstraintEditor.h
Normal file
65
neo/tools/imgui/afeditor/AfConstraintEditor.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../util/Imgui_IdWidgets.h"
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
class AfConstraintEditor
|
||||
{
|
||||
public:
|
||||
|
||||
AfConstraintEditor( idDeclAF* newDecl, idDeclAF_Constraint* newConstraint );
|
||||
~AfConstraintEditor();
|
||||
|
||||
bool Do();
|
||||
bool InputAfVector( idAFVector* afVec );
|
||||
void InitJointLists();
|
||||
|
||||
private:
|
||||
|
||||
idDeclAF* decl;
|
||||
idDeclAF_Constraint* constraint;
|
||||
int anchorType;
|
||||
int shaft1Type;
|
||||
int shaft2Type;
|
||||
int limitOrientationType;
|
||||
int body1;
|
||||
int body2;
|
||||
int jointAnchor1;
|
||||
int jointAnchor2;
|
||||
int jointShaft1;
|
||||
idStr renameConstraint;
|
||||
idStrList joints;
|
||||
};
|
||||
|
||||
}
|
679
neo/tools/imgui/afeditor/AfEditor.cpp
Normal file
679
neo/tools/imgui/afeditor/AfEditor.cpp
Normal file
|
@ -0,0 +1,679 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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 "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AfEditor.h"
|
||||
|
||||
#include "../imgui/BFGimgui.h"
|
||||
#include "../framework/DeclAF.h"
|
||||
|
||||
#include "../util/Imgui_IdWidgets.h"
|
||||
|
||||
extern idCVar af_useLinearTime;
|
||||
extern idCVar af_useImpulseFriction;
|
||||
extern idCVar af_useJointImpulseFriction;
|
||||
extern idCVar af_useSymmetry;
|
||||
extern idCVar af_skipSelfCollision;
|
||||
extern idCVar af_skipLimits;
|
||||
extern idCVar af_skipFriction;
|
||||
extern idCVar af_forceFriction;
|
||||
extern idCVar af_maxLinearVelocity;
|
||||
extern idCVar af_showTimings;
|
||||
extern idCVar af_showConstraints;
|
||||
extern idCVar af_showConstraintNames;
|
||||
extern idCVar af_showConstrainedBodies;
|
||||
extern idCVar af_showPrimaryOnly;
|
||||
extern idCVar af_showTrees;
|
||||
extern idCVar af_showLimits;
|
||||
extern idCVar af_showBodies;
|
||||
extern idCVar af_showBodyNames;
|
||||
extern idCVar af_showMass;
|
||||
extern idCVar af_showTotalMass;
|
||||
extern idCVar af_showInertia;
|
||||
extern idCVar af_showVelocity;
|
||||
extern idCVar af_showActive;
|
||||
extern idCVar af_testSolid;
|
||||
|
||||
namespace
|
||||
{
|
||||
static bool isShown = false;
|
||||
|
||||
static idDeclAF emptyDecl;
|
||||
static idDeclAF_Body emptyBody;
|
||||
static idDeclAF_Constraint emptyConstraint;
|
||||
|
||||
static int linearTolerance = 10;
|
||||
static int angularTolerance = 10;
|
||||
static idStrStatic<256> currentBody;
|
||||
static int bodyLength = 8;
|
||||
static int bodyWidth = 16;
|
||||
static int bodyHeight = 20;
|
||||
|
||||
static const char* bodyTypeNames[] =
|
||||
{
|
||||
"box",
|
||||
"octahedron",
|
||||
"dedecahedron",
|
||||
"cylinder",
|
||||
"cone",
|
||||
"bone",
|
||||
"polygon",
|
||||
"polygonvolume",
|
||||
"custom"
|
||||
};
|
||||
|
||||
int positionType = 0;
|
||||
static const char* positionTypeNames[3] =
|
||||
{
|
||||
"coordinates",
|
||||
"bone center",
|
||||
"joint"
|
||||
};
|
||||
|
||||
bool bodyContentsSelected[5] =
|
||||
{
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
};
|
||||
|
||||
MultiSelectWidget w1 = MakePhysicsContentsSelector();
|
||||
MultiSelectWidget w2 = MakePhysicsContentsSelector();
|
||||
|
||||
int modifyJointType = 0;
|
||||
static const char* modifyJointsNames[3] =
|
||||
{
|
||||
"orientation",
|
||||
"position",
|
||||
"both"
|
||||
};
|
||||
|
||||
int constraintType = 2;
|
||||
static const char* constraintTypeNames[DECLAF_CONSTRAINT_SPRING] =
|
||||
{
|
||||
"fixed",
|
||||
"ballandsocket",
|
||||
"universal",
|
||||
"hinge",
|
||||
"slider",
|
||||
"spring"
|
||||
};
|
||||
|
||||
int constraintLimitType = 1;
|
||||
static const char* constraintLimitTypeNames[3] =
|
||||
{
|
||||
"none",
|
||||
"cone",
|
||||
"pyramid"
|
||||
};
|
||||
|
||||
int shaft1 = 1;
|
||||
int shaft2 = 1;
|
||||
int limitOrientation = 1;
|
||||
static const char* jointPointTypeNames[2] =
|
||||
{
|
||||
"bone",
|
||||
"angles"
|
||||
};
|
||||
|
||||
int anchorType = 0;
|
||||
static const char* anchorTypeNames[2] =
|
||||
{
|
||||
"joint",
|
||||
"coorindates"
|
||||
};
|
||||
}
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
static bool BodyItemGetter( void* data, int index, const char** items );
|
||||
static bool ConstraintItemGetter( void* data, int index, const char** items );
|
||||
|
||||
static bool CVarCheckBox( const char* label, idCVar* cvar );
|
||||
|
||||
AfEditor::AfEditor()
|
||||
: isShown( false )
|
||||
, fileSelection( 0 )
|
||||
, currentAf( 0 )
|
||||
, currentConstraint( 0 )
|
||||
, currentBodySelection( 0 )
|
||||
, currentEntity( 0 )
|
||||
, decl( nullptr )
|
||||
, body( nullptr )
|
||||
, constraint( nullptr )
|
||||
, propertyEditor( nullptr )
|
||||
{
|
||||
}
|
||||
|
||||
AfEditor::~AfEditor()
|
||||
{
|
||||
if( propertyEditor )
|
||||
{
|
||||
delete propertyEditor;
|
||||
}
|
||||
bodyEditors.DeleteContents();
|
||||
constraintEditors.DeleteContents();
|
||||
}
|
||||
|
||||
void AfEditor::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void AfEditor::Draw()
|
||||
{
|
||||
bool showTool = isShown;
|
||||
static char buff[256];
|
||||
|
||||
if( ImGui::Begin( "AF Editor", &showTool, ImGuiWindowFlags_MenuBar ) )
|
||||
{
|
||||
impl::SetReleaseToolMouse( true );
|
||||
|
||||
bool changedAf = false;
|
||||
bool openedAfBrowser = false;
|
||||
bool clickedNew = false;
|
||||
|
||||
if( ImGui::BeginMenuBar() )
|
||||
{
|
||||
if( ImGui::BeginMenu( "File" ) )
|
||||
{
|
||||
if( ImGui::MenuItem( "New", "Ctrl+N" ) )
|
||||
{
|
||||
clickedNew = true;
|
||||
}
|
||||
|
||||
if( ImGui::MenuItem( "Open..", "Ctrl+O" ) )
|
||||
{
|
||||
afList.shouldPopulate = true;
|
||||
openedAfBrowser = true;
|
||||
}
|
||||
|
||||
if( ImGui::MenuItem( "Save", "Ctrl+S" ) )
|
||||
{
|
||||
if( decl )
|
||||
{
|
||||
decl->Save();
|
||||
}
|
||||
}
|
||||
|
||||
// When the editor is closed. it should also set g_editEntities with ~= EDITOR_AF.
|
||||
if( ImGui::MenuItem( "Close", "Ctrl+W" ) )
|
||||
{
|
||||
showTool = false;
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
if( clickedNew )
|
||||
{
|
||||
ImGui::OpenPopup( "New Articulated Figure" );
|
||||
}
|
||||
|
||||
if( ImGui::BeginPopupModal( "New Articulated Figure" ) )
|
||||
{
|
||||
if( afFiles.Num() == 0 )
|
||||
{
|
||||
idFileList* files = fileSystem->ListFiles( "af", ".af", true, true );
|
||||
for( int i = 0; i < files->GetNumFiles(); i++ )
|
||||
{
|
||||
afFiles.Append( files->GetFile( i ) );
|
||||
}
|
||||
fileSystem->FreeFileList( files );
|
||||
}
|
||||
|
||||
ImGui::ListBoxHeader( "##afFileSelect" );
|
||||
for( int i = 0; i < afFiles.Num(); i++ )
|
||||
{
|
||||
if( ImGui::ListBox( "Files", &fileSelection, StringListItemGetter, &afFiles, afFiles.Num() ) )
|
||||
{
|
||||
fileName = afFiles[fileSelection];
|
||||
}
|
||||
}
|
||||
ImGui::ListBoxFooter();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::SmallButton( "New File" );
|
||||
|
||||
ImGui::InputText( "AF Name", &fileName );
|
||||
if( ImGui::Button( "Create" ) )
|
||||
{
|
||||
idStr afName = fileName;
|
||||
afName.StripPath();
|
||||
afName.StripFileExtension();
|
||||
|
||||
if( !afName.IsEmpty() )
|
||||
{
|
||||
idDeclAF* newDecl = static_cast<idDeclAF*>( const_cast<idDecl*>( declManager->FindType( DECL_AF, afName.c_str(), false ) ) );
|
||||
if( !newDecl )
|
||||
{
|
||||
// create it
|
||||
newDecl = static_cast<idDeclAF*>( declManager->CreateNewDecl( DECL_AF, afName.c_str(), fileName.c_str() ) );
|
||||
}
|
||||
|
||||
afList.names.Append( afName );
|
||||
currentAf = afList.names.Num() - 1;
|
||||
|
||||
OnNewDecl( newDecl );
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( "Close" ) )
|
||||
{
|
||||
afFiles.Clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if( openedAfBrowser )
|
||||
{
|
||||
ImGui::OpenPopup( "Articulated Figure Browser" );
|
||||
}
|
||||
|
||||
if( ImGui::BeginPopup( "Articulated Figure Browser" ) )
|
||||
{
|
||||
afList.populate();
|
||||
afList.shouldPopulate = false;
|
||||
if( afList.names.Num() > 0 )
|
||||
{
|
||||
ImGui::Combo( "Articulated Figures", ¤tAf, &StringListItemGetter, &afList, afList.names.Num() );
|
||||
if( ImGui::Button( "Select" ) )
|
||||
{
|
||||
idDeclAF* newDecl = static_cast<idDeclAF*>( const_cast<idDecl*>( declManager->FindType( DECL_AF, afList.names[currentAf], false ) ) );
|
||||
if( newDecl )
|
||||
{
|
||||
OnNewDecl( newDecl );
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui::Text( "There are no articulated figures!" );
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "Close" ) )
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if( decl )
|
||||
{
|
||||
if( ImGui::BeginTabBar( "Tab Bar" ) )
|
||||
{
|
||||
if( ImGui::BeginTabItem( "View" ) )
|
||||
{
|
||||
CVarCheckBox( "Show Bodies", &af_showBodies );
|
||||
CVarCheckBox( "Show Body Names", &af_showBodyNames );
|
||||
CVarCheckBox( "Show Constraints", &af_showConstraints );
|
||||
CVarCheckBox( "Show Constraint Names", &af_showConstraintNames );
|
||||
CVarCheckBox( "Show Limits", &af_showLimits );
|
||||
CVarCheckBox( "Show Active ", &af_showActive );
|
||||
CVarCheckBox( "Show Trees", &af_showTrees );
|
||||
CVarCheckBox( "Show Mass", &af_showMass );
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if( ImGui::BeginTabItem( "Properties" ) )
|
||||
{
|
||||
if( propertyEditor )
|
||||
{
|
||||
changedAf = changedAf || propertyEditor->Do();
|
||||
}
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if( ImGui::BeginTabItem( "Bodies##Tab" ) )
|
||||
{
|
||||
if( decl->bodies.Num() > 0 )
|
||||
{
|
||||
ImGui::Combo( "Body", ¤tBodySelection, BodyItemGetter, decl, decl->bodies.Num() );
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
static char bodyName[256] = { '\0' };
|
||||
|
||||
if( ImGui::Button( "New Body" ) )
|
||||
{
|
||||
ImGui::OpenPopup( "Create a New Body" );
|
||||
}
|
||||
if( ImGui::BeginPopup( "Create a New Body" ) )
|
||||
{
|
||||
ImGui::Text( "Create a new body for the articulated figure" );
|
||||
ImGui::InputText( "Body Name", &bodyName[0], 256 );
|
||||
if( ImGui::Button( "Create" ) )
|
||||
{
|
||||
// added a new body
|
||||
if( strlen( bodyName ) > 0 )
|
||||
{
|
||||
// TODO: Should do some data validation on the body name.
|
||||
decl->NewBody( bodyName );
|
||||
bodyName[0] = '\0';
|
||||
currentBodySelection = decl->bodies.Num() - 1;
|
||||
bodyEditors.Append( new AfBodyEditor( decl, decl->bodies[currentBodySelection] ) );
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( "Cancel" ) )
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if( bodyEditors.Num() > currentBodySelection )
|
||||
{
|
||||
changedAf = changedAf || bodyEditors[currentBodySelection]->Do();
|
||||
|
||||
if( ImGui::Button( "Delete Body" ) )
|
||||
{
|
||||
ImGui::OpenPopup( "Delete Body##2" );
|
||||
}
|
||||
|
||||
if( ImGui::BeginPopupModal( "Delete Body##2" ) )
|
||||
{
|
||||
ImGui::Text( "Are you sure you want to delete body %s?", decl->bodies[currentBodySelection]->name.c_str() );
|
||||
|
||||
if( ImGui::Button( "Yes" ) )
|
||||
{
|
||||
delete bodyEditors[currentBodySelection];
|
||||
bodyEditors.RemoveIndex( currentBodySelection );
|
||||
decl->DeleteBody( decl->bodies[currentBodySelection]->name.c_str() );
|
||||
currentBodySelection -= 1;
|
||||
if( currentBodySelection < 0 )
|
||||
{
|
||||
currentBodySelection = 0;
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if( ImGui::Button( "No" ) )
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if( ImGui::BeginTabItem( "Constraints" ) )
|
||||
{
|
||||
if( decl->constraints.Num() > 0 )
|
||||
{
|
||||
ImGui::Combo( "Constraint", ¤tConstraint, ConstraintItemGetter, decl, decl->constraints.Num() );
|
||||
}
|
||||
|
||||
static char constraintName[256] = { '\0' };
|
||||
|
||||
if( ImGui::Button( "New" ) )
|
||||
{
|
||||
ImGui::OpenPopup( "New Constraint" );
|
||||
}
|
||||
|
||||
if( ImGui::BeginPopupModal( "New Constraint" ) )
|
||||
{
|
||||
ImGui::Text( "Create a new body for the articulated figure" );
|
||||
ImGui::InputText( "Constraint Name", &constraintName[0], 256 );
|
||||
|
||||
if( ImGui::Button( "Create" ) )
|
||||
{
|
||||
// added a new body
|
||||
if( strlen( constraintName ) > 0 )
|
||||
{
|
||||
decl->NewConstraint( constraintName );
|
||||
constraintEditors.Append( new AfConstraintEditor( decl, decl->constraints[decl->constraints.Num() - 1] ) );
|
||||
currentConstraint = constraintEditors.Num() - 1;
|
||||
}
|
||||
constraintName[0] = '\0';
|
||||
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "Cancel" ) )
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "Delete" ) )
|
||||
{
|
||||
ImGui::OpenPopup( "Delete Constraint##2" );
|
||||
}
|
||||
|
||||
if( ImGui::BeginPopupModal( "Delete Constraint##2" ) )
|
||||
{
|
||||
ImGui::Text( "Are you sure you want to delete constraint %s?", decl->constraints[currentConstraint]->name.c_str() );
|
||||
|
||||
if( ImGui::Button( "Yes" ) )
|
||||
{
|
||||
delete constraintEditors[currentConstraint];
|
||||
constraintEditors.RemoveIndex( currentConstraint );
|
||||
decl->DeleteConstraint( decl->constraints[currentConstraint]->name.c_str() );
|
||||
currentConstraint -= 1;
|
||||
if( currentConstraint < 0 )
|
||||
{
|
||||
currentConstraint = 0;
|
||||
}
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "No" ) )
|
||||
{
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if( decl->constraints.Num() > currentConstraint )
|
||||
{
|
||||
changedAf = constraintEditors[currentConstraint]->Do();
|
||||
}
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::Separator();
|
||||
ImGui::NewLine();
|
||||
|
||||
try
|
||||
{
|
||||
if( ImGui::Button( "Spawn" ) )
|
||||
{
|
||||
if( afList.names.Num() > currentAf )
|
||||
{
|
||||
gameEdit->AF_SpawnEntity( afList.names[currentAf].c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if( ImGui::Button( "Kill" ) )
|
||||
{
|
||||
cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "deleteSelected\n" );
|
||||
}
|
||||
|
||||
if( changedAf )
|
||||
{
|
||||
if( afList.names.Num() > currentAf )
|
||||
{
|
||||
gameEdit->AF_UpdateEntities( afList.names[currentAf].c_str() );
|
||||
}
|
||||
}
|
||||
}
|
||||
catch( idException& exception )
|
||||
{
|
||||
common->DWarning( "AfEditor exception %s", exception.GetError() );
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
if( isShown && !showTool )
|
||||
{
|
||||
// TODO: do the same as when pressing cancel?
|
||||
isShown = showTool;
|
||||
impl::SetReleaseToolMouse( false );
|
||||
}
|
||||
}
|
||||
|
||||
void AfEditor::OnNewDecl( idDeclAF* newDecl )
|
||||
{
|
||||
decl = newDecl;
|
||||
if( propertyEditor )
|
||||
{
|
||||
delete propertyEditor;
|
||||
}
|
||||
bodyEditors.DeleteContents();
|
||||
constraintEditors.DeleteContents();
|
||||
|
||||
propertyEditor = new AfPropertyEditor( newDecl );
|
||||
|
||||
for( int i = 0; i < decl->bodies.Num(); i++ )
|
||||
{
|
||||
bodyEditors.Append( new AfBodyEditor( decl, decl->bodies[i] ) );
|
||||
}
|
||||
|
||||
for( int i = 0; i < decl->constraints.Num(); i++ )
|
||||
{
|
||||
constraintEditors.Append( new AfConstraintEditor( decl, decl->constraints[i] ) );
|
||||
}
|
||||
}
|
||||
|
||||
AfEditor& AfEditor::Instance()
|
||||
{
|
||||
static AfEditor instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void AfEditor::Enable( const idCmdArgs& args )
|
||||
{
|
||||
AfEditor::Instance().ShowIt( true );
|
||||
}
|
||||
|
||||
void AfEditor::AfList::populate()
|
||||
{
|
||||
if( !shouldPopulate )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
names.Clear();
|
||||
|
||||
int count = declManager->GetNumDecls( DECL_AF );
|
||||
for( int i = 0; i < count; i++ )
|
||||
{
|
||||
names.Append( static_cast<const idDeclAF*>( declManager->DeclByIndex( DECL_AF, i, false ) )->GetName() );
|
||||
}
|
||||
}
|
||||
|
||||
bool BodyItemGetter( void* data, int index, const char** itemName )
|
||||
{
|
||||
idDeclAF* decl = reinterpret_cast<idDeclAF*>( data );
|
||||
if( !decl )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( index > decl->bodies.Num() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
idDeclAF_Body* body = decl->bodies[index];
|
||||
|
||||
*itemName = body->name.c_str();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ConstraintItemGetter( void* data, int index, const char** items )
|
||||
{
|
||||
idDeclAF* decl = reinterpret_cast<idDeclAF*>( data );
|
||||
if( !decl )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if( index > decl->constraints.Num() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
idDeclAF_Constraint* constraint = decl->constraints[index];
|
||||
|
||||
*items = constraint->name.c_str();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CVarCheckBox( const char* label, idCVar* cvar )
|
||||
{
|
||||
bool value = cvar->GetBool();
|
||||
if( ImGui::Checkbox( label, &value ) )
|
||||
{
|
||||
cvar->SetBool( value );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
122
neo/tools/imgui/afeditor/AfEditor.h
Normal file
122
neo/tools/imgui/afeditor/AfEditor.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef EDITOR_TOOLS_AFEDITOR_H_
|
||||
#define EDITOR_TOOLS_AFEDITOR_H_
|
||||
|
||||
#include "../../edit_public.h"
|
||||
|
||||
#include "AfBodyEditor.h"
|
||||
#include "AfConstraintEditor.h"
|
||||
#include "AfPropertyEditor.h"
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
/**
|
||||
* Articulated figure imgui editor.
|
||||
*/
|
||||
class AfEditor
|
||||
{
|
||||
public:
|
||||
virtual ~AfEditor();
|
||||
|
||||
void Init();
|
||||
|
||||
void ShowIt( bool show );
|
||||
|
||||
bool IsShown() const;
|
||||
|
||||
void Draw();
|
||||
|
||||
public:
|
||||
|
||||
static AfEditor& Instance();
|
||||
static void Enable( const idCmdArgs& args );
|
||||
|
||||
public:
|
||||
|
||||
AfEditor( AfEditor const& ) = delete;
|
||||
void operator=( AfEditor const& ) = delete;
|
||||
|
||||
private:
|
||||
|
||||
struct AfList
|
||||
{
|
||||
AfList() : names(), shouldPopulate( false ) {}
|
||||
void populate();
|
||||
|
||||
idList<idStr> names;
|
||||
bool shouldPopulate;
|
||||
};
|
||||
|
||||
AfEditor();
|
||||
|
||||
void OnNewDecl( idDeclAF* newDecl );
|
||||
|
||||
bool isShown;
|
||||
int fileSelection;
|
||||
int currentAf;
|
||||
int currentConstraint;
|
||||
int currentBodySelection;
|
||||
int currentEntity;
|
||||
idDeclAF* decl;
|
||||
idDeclAF_Body* body;
|
||||
idDeclAF_Constraint* constraint;
|
||||
|
||||
// Editor dialogs
|
||||
AfPropertyEditor* propertyEditor;
|
||||
idList<AfBodyEditor*> bodyEditors;
|
||||
idList<AfConstraintEditor*> constraintEditors;
|
||||
|
||||
AfList afList; // list with idDeclAF names
|
||||
idList<idStr> afFiles;
|
||||
idStr fileName;
|
||||
|
||||
struct IndexEntityDef
|
||||
{
|
||||
int index;
|
||||
idStr name;
|
||||
};
|
||||
idList<IndexEntityDef> entities;
|
||||
};
|
||||
|
||||
inline void AfEditor::ShowIt( bool show )
|
||||
{
|
||||
isShown = show;
|
||||
}
|
||||
|
||||
inline bool AfEditor::IsShown() const
|
||||
{
|
||||
return isShown;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
139
neo/tools/imgui/afeditor/AfPropertyEditor.cpp
Normal file
139
neo/tools/imgui/afeditor/AfPropertyEditor.cpp
Normal file
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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 "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "AfPropertyEditor.h"
|
||||
|
||||
#include "../imgui/BFGimgui.h"
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
AfPropertyEditor::AfPropertyEditor( idDeclAF* newDecl )
|
||||
: decl( newDecl )
|
||||
, contentWidget( MakePhysicsContentsSelector() )
|
||||
, clipMaskWidget( MakePhysicsContentsSelector() )
|
||||
, linearTolerance( 0 )
|
||||
, angularTolerance( 0 )
|
||||
, currentModel( 0 )
|
||||
{
|
||||
contentWidget.UpdateWithBitFlags( decl->contents );
|
||||
clipMaskWidget.UpdateWithBitFlags( decl->clipMask );
|
||||
|
||||
UpdateModelDefList();
|
||||
}
|
||||
|
||||
AfPropertyEditor::~AfPropertyEditor()
|
||||
{
|
||||
}
|
||||
|
||||
bool AfPropertyEditor::Do()
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if( ImGui::CollapsingHeader( "MD5" ) )
|
||||
{
|
||||
if( ImGui::Combo( "Models", ¤tModel, StringListItemGetter, &modelDefs, modelDefs.Num() ) )
|
||||
{
|
||||
decl->model = modelDefs[currentModel];
|
||||
changed = true;
|
||||
}
|
||||
ImGui::InputText( "Skin", &decl->skin, ImGuiInputTextFlags_CharsNoBlank );
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Default Collision Detection" ) )
|
||||
{
|
||||
ImGui::Checkbox( "Self Collision", &decl->selfCollision );
|
||||
ImGui::ListBoxHeader( "Contents" );
|
||||
changed = DoMultiSelect( &contentWidget, &decl->contents ) || changed;
|
||||
ImGui::ListBoxFooter();
|
||||
|
||||
ImGui::ListBoxHeader( "Clip Mask" );
|
||||
changed = DoMultiSelect( &clipMaskWidget, &decl->clipMask ) || changed;
|
||||
ImGui::ListBoxFooter();
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Default Friction" ) )
|
||||
{
|
||||
changed = ImGui::DragFloat( "Linear", &decl->defaultLinearFriction, 0.01f, -100000.f, 100000.f, "%.2f" ) || changed;
|
||||
changed = ImGui::DragFloat( "Angular", &decl->defaultAngularFriction, 0.01f, -100000.f, 100000.f, "%.2f" ) || changed;
|
||||
changed = ImGui::DragFloat( "Contact", &decl->defaultContactFriction, 0.01f, -100000.f, 100000.f, "%.2f" ) || changed;
|
||||
changed = ImGui::DragFloat( "Constraint", &decl->defaultConstraintFriction, 0.01f, -100000.f, 100000.f, "%.2f" ) || changed;
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Mass" ) )
|
||||
{
|
||||
changed = changed || ImGui::InputFloat( "Total Mass", &decl->totalMass, 1.0f, 50.0f, "%.0f" );
|
||||
ImGui::SameLine();
|
||||
HelpMarker( "The total mass of the articulated figure.\n"
|
||||
"If the total mass is set to a value greater than\n"
|
||||
"zero then the mass of each body is scaled such that\n"
|
||||
"the total mass of the articulated figure equals the given mass." );
|
||||
}
|
||||
|
||||
if( ImGui::CollapsingHeader( "Suspend Speed" ) )
|
||||
{
|
||||
changed = changed || ImGui::InputFloat2( "Linear Velocity", ( float* )&decl->suspendVelocity, "%.0f" );
|
||||
changed = changed || ImGui::InputFloat2( "Linear Acceleration", ( float* )&decl->suspendAcceleration, "%.0f" );
|
||||
}
|
||||
|
||||
// TODO(Stephen): Figure out what these properties are for.
|
||||
//if (ImGui::CollapsingHeader("Suspend Movement"))
|
||||
//{
|
||||
// ImGui::InputInt("No Move Time", (int*)&decl->noMoveTime);
|
||||
// ImGui::InputInt("Linear Tolerance", &linearTolerance);
|
||||
// ImGui::InputInt("Angular Tolerance", &angularTolerance);
|
||||
// ImGui::InputInt("Minimum Move Time", (int*)&decl->minMoveTime);
|
||||
// ImGui::InputInt("Maximum Move Time", (int*)&decl->maxMoveTime);
|
||||
//}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
void AfPropertyEditor::UpdateModelDefList()
|
||||
{
|
||||
// update the model list.
|
||||
const int totalModelDefs = declManager->GetNumDecls( DECL_MODELDEF );
|
||||
modelDefs.AssureSize( totalModelDefs );
|
||||
for( int i = 0; i < totalModelDefs; i++ )
|
||||
{
|
||||
const idDecl* modelDef = declManager->DeclByIndex( DECL_MODELDEF, i, false );
|
||||
if( modelDef )
|
||||
{
|
||||
modelDefs[i] = modelDef->GetName();
|
||||
if( decl->model == modelDef->GetName() )
|
||||
{
|
||||
currentModel = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
62
neo/tools/imgui/afeditor/AfPropertyEditor.h
Normal file
62
neo/tools/imgui/afeditor/AfPropertyEditor.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#ifndef EDITOR_TOOLS_AFPROPERTYEDITOR_H_
|
||||
#define EDITOR_TOOLS_AFPROPERTYEDITOR_H_
|
||||
|
||||
#include "../util/Imgui_IdWidgets.h"
|
||||
|
||||
namespace ImGuiTools
|
||||
{
|
||||
|
||||
class AfPropertyEditor
|
||||
{
|
||||
public:
|
||||
AfPropertyEditor( idDeclAF* newDecl );
|
||||
~AfPropertyEditor();
|
||||
|
||||
bool Do();
|
||||
|
||||
private:
|
||||
|
||||
void UpdateModelDefList();
|
||||
|
||||
idDeclAF* decl;
|
||||
MultiSelectWidget contentWidget;
|
||||
MultiSelectWidget clipMaskWidget;
|
||||
int linearTolerance;
|
||||
int angularTolerance;
|
||||
int currentModel;
|
||||
|
||||
idStrList modelDefs;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
131
neo/tools/imgui/util/Imgui_IdWidgets.cpp
Normal file
131
neo/tools/imgui/util/Imgui_IdWidgets.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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 "precompiled.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "../imgui/imgui.h"
|
||||
|
||||
#include "Imgui_IdWidgets.h"
|
||||
|
||||
static const char* bodyContentsNames[5] =
|
||||
{
|
||||
"solid",
|
||||
"body",
|
||||
"corpse",
|
||||
"playerclip",
|
||||
"monsterclip"
|
||||
};
|
||||
|
||||
static int contentMappingFlags[5] =
|
||||
{
|
||||
CONTENTS_SOLID,
|
||||
CONTENTS_BODY,
|
||||
CONTENTS_CORPSE,
|
||||
CONTENTS_PLAYERCLIP,
|
||||
CONTENTS_MONSTERCLIP
|
||||
};
|
||||
|
||||
MultiSelectWidget::MultiSelectWidget( const char** aNames, int* contentMapping, int aNumEntries )
|
||||
: names( aNames )
|
||||
, contentMapping( contentMapping )
|
||||
, numEntries( aNumEntries )
|
||||
, selectables( nullptr )
|
||||
{
|
||||
selectables = ( bool* )Mem_Alloc( numEntries * sizeof( bool ), TAG_AF );
|
||||
std::fill( selectables, selectables + numEntries, false );
|
||||
}
|
||||
|
||||
MultiSelectWidget::~MultiSelectWidget()
|
||||
{
|
||||
Mem_Free( selectables );
|
||||
}
|
||||
|
||||
void MultiSelectWidget::Update( int index, bool value )
|
||||
{
|
||||
assert( index < numEntries );
|
||||
selectables[index] = value;
|
||||
}
|
||||
|
||||
void MultiSelectWidget::UpdateWithBitFlags( int bitFlags )
|
||||
{
|
||||
for( int i = 0; i < numEntries; i++ )
|
||||
{
|
||||
Update( i, bitFlags & contentMapping[i] );
|
||||
}
|
||||
}
|
||||
|
||||
bool DoMultiSelect( MultiSelectWidget* widget, int* contents )
|
||||
{
|
||||
bool pressed = false;
|
||||
for( int i = 0; i < 5; i++ )
|
||||
{
|
||||
if( ImGui::Selectable( widget->names[i], &widget->selectables[i] ) )
|
||||
{
|
||||
pressed = true;
|
||||
if( widget->selectables[i] )
|
||||
{
|
||||
*contents |= widget->contentMapping[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
*contents &= ~widget->contentMapping[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pressed;
|
||||
}
|
||||
|
||||
void HelpMarker( const char* desc )
|
||||
{
|
||||
ImGui::TextDisabled( "(?)" );
|
||||
if( ImGui::IsItemHovered() )
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::PushTextWrapPos( ImGui::GetFontSize() * 35.0f );
|
||||
ImGui::TextUnformatted( desc );
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
bool StringListItemGetter( void* data, int index, const char** outText )
|
||||
{
|
||||
idStrList* list = reinterpret_cast<idStrList*>( data );
|
||||
assert( index < list->Num() );
|
||||
|
||||
*outText = ( *list )[index];
|
||||
return true;
|
||||
}
|
||||
|
||||
MultiSelectWidget MakePhysicsContentsSelector()
|
||||
{
|
||||
return MultiSelectWidget( bodyContentsNames, contentMappingFlags, 5 );
|
||||
}
|
59
neo/tools/imgui/util/Imgui_IdWidgets.h
Normal file
59
neo/tools/imgui/util/Imgui_IdWidgets.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
===========================================================================
|
||||
|
||||
Doom 3 GPL Source Code
|
||||
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
|
||||
Copyright (C) 2022 Stephen Pridham
|
||||
|
||||
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.
|
||||
|
||||
===========================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* Holds a list of booleans that correspond to a list of names. This
|
||||
* class owns the list of bools, not the list of names.
|
||||
*/
|
||||
class MultiSelectWidget
|
||||
{
|
||||
public:
|
||||
MultiSelectWidget( const char** aNames, int* contentMapping, int aNumEntries );
|
||||
~MultiSelectWidget();
|
||||
|
||||
void Update( int index, bool value );
|
||||
|
||||
void UpdateWithBitFlags( int bitFlags );
|
||||
|
||||
public:
|
||||
const char** names;
|
||||
int* contentMapping;
|
||||
int numEntries;
|
||||
bool* selectables;
|
||||
};
|
||||
|
||||
bool DoMultiSelect( MultiSelectWidget* widget, int* contents );
|
||||
|
||||
void HelpMarker( const char* desc );
|
||||
|
||||
bool StringListItemGetter( void* data, int index, const char** outText );
|
||||
|
||||
MultiSelectWidget MakePhysicsContentsSelector();
|
Loading…
Reference in a new issue