├── .cproject ├── .gitignore ├── .project ├── .settings └── org.eclipse.cdt.codan.core.prefs ├── CMakeLists.txt ├── GUI ├── About.ui ├── AnimationPanel.cpp ├── AnimationPanel.h ├── AnimationPanel.ui ├── EditorWindow.cpp ├── EditorWindow.h ├── Main.cpp ├── MainWindow.cpp ├── MainWindow.h ├── MainWindow.ui ├── OffScreenRenderer.cpp ├── OffScreenRenderer.h ├── ProgramState.cpp ├── ProgramState.h ├── SidePanel.cpp ├── SidePanel.h ├── SidePanel.ui ├── icon │ ├── i.iconset │ │ └── icon_32x32.png │ ├── icon.png │ ├── macicon.icns │ ├── winicon.ico │ └── winicon.rc ├── resources │ ├── add.png │ ├── backward.png │ ├── pause.png │ ├── play.png │ ├── repeat.png │ └── resources.rc └── widgets │ ├── ActionButton.cpp │ └── ActionButton.h ├── README.txt ├── core ├── BDMORPH.cpp ├── BDMORPH.h ├── KVFModel.cpp ├── KVFModel.h ├── MeshModel.cpp ├── MeshModel.h ├── OutlineModel.cpp ├── OutlineModel.h ├── VideoModel.cpp └── VideoModel.h └── utils ├── cholmod_common.cpp ├── cholmod_common.h ├── cholmod_matrix.cpp ├── cholmod_matrix.h ├── cholmod_vector.h ├── ffmpeg_encoder.cpp ├── ffmpeg_encoder.h ├── triangle.c ├── triangle.h ├── utils.cpp ├── utils.h ├── vector2d.cpp └── vector2d.h /.cproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 41 | 42 | 43 | 44 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | KVF 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 10 | clean,full,incremental, 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 16 | full,incremental, 17 | 18 | 19 | 20 | 21 | 22 | org.eclipse.cdt.core.cnature 23 | org.eclipse.cdt.core.ccnature 24 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 25 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 26 | 27 | 28 | -------------------------------------------------------------------------------- /.settings/org.eclipse.cdt.codan.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.cdt.codan.checkers.errnoreturn=Warning 3 | org.eclipse.cdt.codan.checkers.errnoreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} 4 | org.eclipse.cdt.codan.checkers.errreturnvalue=Error 5 | org.eclipse.cdt.codan.checkers.errreturnvalue.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 6 | org.eclipse.cdt.codan.checkers.noreturn=Error 7 | org.eclipse.cdt.codan.checkers.noreturn.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},implicit\=>false} 8 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation=Error 9 | org.eclipse.cdt.codan.internal.checkers.AbstractClassCreation.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 10 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem=Error 11 | org.eclipse.cdt.codan.internal.checkers.AmbiguousProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 12 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem=Warning 13 | org.eclipse.cdt.codan.internal.checkers.AssignmentInConditionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 14 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem=Error 15 | org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 16 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem=Warning 17 | org.eclipse.cdt.codan.internal.checkers.CaseBreakProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},no_break_comment\=>"no break",last_case_param\=>false,empty_case_param\=>false} 18 | org.eclipse.cdt.codan.internal.checkers.CatchByReference=Warning 19 | org.eclipse.cdt.codan.internal.checkers.CatchByReference.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},unknown\=>false,exceptions\=>()} 20 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem=Error 21 | org.eclipse.cdt.codan.internal.checkers.CircularReferenceProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 22 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization=Warning 23 | org.eclipse.cdt.codan.internal.checkers.ClassMembersInitialization.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},skip\=>true} 24 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem=Error 25 | org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 26 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem=Error 27 | org.eclipse.cdt.codan.internal.checkers.FunctionResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 28 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments=Error 29 | org.eclipse.cdt.codan.internal.checkers.InvalidArguments.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 30 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem=Error 31 | org.eclipse.cdt.codan.internal.checkers.InvalidTemplateArgumentsProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 32 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem=Error 33 | org.eclipse.cdt.codan.internal.checkers.LabelStatementNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 34 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem=Error 35 | org.eclipse.cdt.codan.internal.checkers.MemberDeclarationNotFoundProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 36 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem=Error 37 | org.eclipse.cdt.codan.internal.checkers.MethodResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 38 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker=-Info 39 | org.eclipse.cdt.codan.internal.checkers.NamingConventionFunctionChecker.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},pattern\=>"^[a-z]",macro\=>true,exceptions\=>()} 40 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem=Warning 41 | org.eclipse.cdt.codan.internal.checkers.NonVirtualDestructorProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 42 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem=Error 43 | org.eclipse.cdt.codan.internal.checkers.OverloadProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 44 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem=Error 45 | org.eclipse.cdt.codan.internal.checkers.RedeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 46 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem=Error 47 | org.eclipse.cdt.codan.internal.checkers.RedefinitionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 48 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem=-Warning 49 | org.eclipse.cdt.codan.internal.checkers.ReturnStyleProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 50 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem=-Warning 51 | org.eclipse.cdt.codan.internal.checkers.ScanfFormatStringSecurityProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 52 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem=Warning 53 | org.eclipse.cdt.codan.internal.checkers.StatementHasNoEffectProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>()} 54 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem=Warning 55 | org.eclipse.cdt.codan.internal.checkers.SuggestedParenthesisProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},paramNot\=>false} 56 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem=Warning 57 | org.eclipse.cdt.codan.internal.checkers.SuspiciousSemicolonProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},else\=>false,afterelse\=>false} 58 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem=Error 59 | org.eclipse.cdt.codan.internal.checkers.TypeResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 60 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem=Warning 61 | org.eclipse.cdt.codan.internal.checkers.UnusedFunctionDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} 62 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem=Warning 63 | org.eclipse.cdt.codan.internal.checkers.UnusedStaticFunctionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true} 64 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem=Warning 65 | org.eclipse.cdt.codan.internal.checkers.UnusedVariableDeclarationProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true},macro\=>true,exceptions\=>("@(\#)","$Id")} 66 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem=Error 67 | org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem.params={launchModes\=>{RUN_ON_FULL_BUILD\=>true,RUN_ON_INC_BUILD\=>true,RUN_ON_FILE_OPEN\=>false,RUN_ON_FILE_SAVE\=>false,RUN_AS_YOU_TYPE\=>true,RUN_ON_DEMAND\=>true}} 68 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.6) 2 | 3 | PROJECT(bdmorph) 4 | FIND_PACKAGE(Qt4 REQUIRED) 5 | FIND_PACKAGE(OpenGL REQUIRED) 6 | SET(QT_USE_QTOPENGL TRUE) 7 | INCLUDE(${QT_USE_FILE}) 8 | 9 | if(NOT CMAKE_BUILD_TYPE) 10 | set(CMAKE_BUILD_TYPE "Release" CACHE STRING 11 | "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." 12 | FORCE) 13 | endif(NOT CMAKE_BUILD_TYPE) 14 | 15 | ################################################################################################### 16 | 17 | if (WIN32) 18 | SET(ROOT C:/Users/mlevtsky/Workspace/external) 19 | SET (EXTERNAL_LIBRARIES 20 | ${ROOT}/lib/libamd.lib 21 | ${ROOT}/lib/libcamd.lib 22 | ${ROOT}/lib/libcolamd.lib 23 | ${ROOT}/lib/libccolamd.lib 24 | ${ROOT}/lib/libcholmod.lib 25 | 26 | ${ROOT}/lib/libgoto_CHOLMOD.lib 27 | ${ROOT}/lib/libmetis_CHOLMOD.lib 28 | 29 | ${ROOT}/lib/avcodec.lib 30 | ${ROOT}/lib/avformat.lib 31 | ${ROOT}/lib/avutil.lib 32 | ${ROOT}/lib/swscale.lib 33 | ) 34 | 35 | SET(EXTERNAL_INCLUDES 36 | ${ROOT}/include/ 37 | ${ROOT}/include/suitesparse/ 38 | ) 39 | 40 | SET(ICON_RC_FILE GUI/icon/winicon.rc) 41 | 42 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -DNOMINMAX -D_USE_MATH_DEFINES ") 43 | set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -DNOMINMAX -D_USE_MATH_DEFINES ") 44 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /OPT:NOREF" ) 45 | 46 | endif(WIN32) 47 | 48 | ################################################################################################### 49 | 50 | if (APPLE) 51 | SET (EXTERNAL_LIBRARIES 52 | cholmod amd camd colamd suitesparseconfig 53 | blas lapack 54 | 55 | avcodec avformat avutil swscale swresample 56 | "-framework CoreFoundation" 57 | "-framework CoreVideo" 58 | "-framework VideoDecodeAcceleration" 59 | x264 z bz2 iconv 60 | ) 61 | 62 | SET (EXTERNAL_INCLUDES 63 | /usr/local/include/suitesparse 64 | ) 65 | 66 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder") 67 | 68 | set(MACOSX_BUNDLE_ICON_FILE macicon.icns) 69 | 70 | set(bdmorph_ICON ${CMAKE_CURRENT_SOURCE_DIR}/GUI/icon/macicon.icns) 71 | set_source_files_properties(${bdmorph_ICON} PROPERTIES 72 | MACOSX_PACKAGE_LOCATION "Resources") 73 | 74 | SET(ICON_RC_FILE ${bdmorph_ICON}) 75 | 76 | endif(APPLE) 77 | 78 | ################################################################################################### 79 | 80 | if (NOT APPLE AND UNIX) # <- this is the way it should be 81 | SET (EXTERNAL_LIBRARIES 82 | cholmod amd camd colamd 83 | openblas lapack 84 | avcodec avformat avutil swscale 85 | ) 86 | 87 | SET (EXTERNAL_INCLUDES 88 | /usr/include/suitesparse 89 | ) 90 | 91 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wno-reorder -Woverloaded-virtual") 92 | endif(NOT APPLE AND UNIX) 93 | 94 | ################################################################################################### 95 | 96 | INCLUDE_DIRECTORIES( 97 | ${CMAKE_CURRENT_BINARY_DIR} 98 | ${EXTERNAL_INCLUDES} 99 | . ./GUI ./core ./utils ./GUI/widgets 100 | ) 101 | 102 | SET(bdmorph_SOURCES 103 | GUI/EditorWindow.cpp GUI/Main.cpp GUI/MainWindow.cpp 104 | GUI/SidePanel.cpp GUI/AnimationPanel.cpp GUI/OffScreenRenderer.cpp 105 | GUI/widgets/ActionButton.cpp GUI/ProgramState.cpp 106 | 107 | core/MeshModel.cpp core/KVFModel.cpp core/VideoModel.cpp 108 | core/BDMORPH.cpp core/OutlineModel.cpp 109 | 110 | utils/cholmod_matrix.cpp utils/cholmod_common.cpp utils/vector2d.cpp 111 | utils/triangle.c utils/utils.cpp utils/ffmpeg_encoder.cpp 112 | 113 | ) 114 | 115 | SET(bdmorph_HEADERS_QT 116 | GUI/EditorWindow.h GUI/MainWindow.h GUI/SidePanel.h 117 | GUI/AnimationPanel.h GUI/OffScreenRenderer.h GUI/widgets/ActionButton.h 118 | GUI/ProgramState.h 119 | ) 120 | 121 | SET(bdmorph_HEADERS 122 | ${bdmorph_HEADERS_QT} 123 | core/MeshModel.h core/KVFModel.h core/VideoModel.h 124 | core/BDMORPH.h core/OutlineModel.h 125 | 126 | utils/cholmod_matrix.h utils/cholmod_common.h utils/vector2d.h 127 | utils/triangle.h utils/utils.h 128 | utils/ffmpeg_encoder.h 129 | ) 130 | 131 | SET(bdmorph_FORMS 132 | GUI/MainWindow.ui GUI/SidePanel.ui GUI/AnimationPanel.ui GUI/About.ui 133 | ) 134 | 135 | SET(bdmorph_RESOURCES GUI/resources/resources.rc ) 136 | 137 | ################################################################################################### 138 | 139 | QT4_WRAP_CPP(bdmorph_HEADERS_MOC ${bdmorph_HEADERS_QT}) 140 | QT4_WRAP_UI(bdmorph_FORMS_HEADERS ${bdmorph_FORMS}) 141 | QT4_ADD_RESOURCES(bdmorph_RESOURCES_RCC ${bdmorph_RESOURCES}) 142 | 143 | ADD_EXECUTABLE(bdmorph WIN32 MACOSX_BUNDLE 144 | ${bdmorph_SOURCES} 145 | ${bdmorph_RESOURCES_RCC} 146 | ${bdmorph_HEADERS_MOC} 147 | ${bdmorph_FORMS_HEADERS} 148 | ${bdmorph_HEADERS} 149 | ${ICON_RC_FILE} 150 | ) 151 | 152 | TARGET_LINK_LIBRARIES(bdmorph 153 | ${QT_LIBRARIES} 154 | ${OPENGL_LIBRARIES} 155 | ${EXTERNAL_LIBRARIES} 156 | ) 157 | 158 | 159 | ################################################################################################### 160 | 161 | -------------------------------------------------------------------------------- /GUI/About.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | aboutDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 693 10 | 307 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | :/MainWindow/icon/icon.png:/MainWindow/icon/icon.png 19 | 20 | 21 | 22 | 23 | 24 | <html><head/><body><p>Animation program based on following papers:</p><p><span style=" font-weight:600;">&quot;As-Killing-As-Possible Vector Fields for Planar Deformation&quot;</span></p><p><span style=" font-weight:600;">&quot;Planar Shape Interpolation with Bounded Distortion&quot;</span></p><p>Based on <a href="http://www.cs.technion.ac.il/~cggc/Upload/Projects/KVFDeformation/download.html"><span style=" text-decoration: underline; color:#0000ff;">KVFDeformation</span></a></p><p>Implemented by Maxim Levitsky &amp; Inbar Donag</p></body></html> 25 | 26 | 27 | Qt::AlignCenter 28 | 29 | 30 | false 31 | 32 | 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 0 42 | 0 43 | 44 | 45 | 46 | 47 | 256 48 | 256 49 | 50 | 51 | 52 | 53 | 54 | 55 | :/MainWindow/icon/icon.png 56 | 57 | 58 | true 59 | 60 | 61 | 62 | 63 | 64 | 65 | Qt::Horizontal 66 | 67 | 68 | QDialogButtonBox::Ok 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | buttonBox 80 | accepted() 81 | aboutDialog 82 | accept() 83 | 84 | 85 | 248 86 | 254 87 | 88 | 89 | 157 90 | 274 91 | 92 | 93 | 94 | 95 | buttonBox 96 | rejected() 97 | aboutDialog 98 | reject() 99 | 100 | 101 | 316 102 | 260 103 | 104 | 105 | 286 106 | 274 107 | 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /GUI/AnimationPanel.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "AnimationPanel.h" 14 | #include "VideoModel.h" 15 | #include "MeshModel.h" 16 | #include "OffScreenRenderer.h" 17 | #include "utils.h" 18 | 19 | #define INTEREVAL (1000/60) 20 | 21 | /******************************************************************************************************************************/ 22 | AnimationPanel::AnimationPanel(QWidget* parent) : 23 | QDockWidget(parent), programstate(NULL) 24 | { 25 | setupUi(this); 26 | plusIcon = QIcon(":/AnimationPanel/add.png"); 27 | 28 | cloneAction = new QAction("Clone frame", lstKeyFrames); 29 | deleteFramesAction = new QAction("Delete frame", lstKeyFrames); 30 | changeTimeAction = new QAction("Change time...", lstKeyFrames); 31 | loadKeyframe = new QAction("Load from file...", lstKeyFrames); 32 | 33 | lstKeyFrames->addAction(cloneAction); 34 | lstKeyFrames->addAction(deleteFramesAction); 35 | lstKeyFrames->addAction(changeTimeAction); 36 | lstKeyFrames->addAction(loadKeyframe); 37 | lstKeyFrames->setContextMenuPolicy(Qt::ActionsContextMenu); 38 | 39 | /* Play/pause buttons */ 40 | connect_(btnAnimationPlay, clicked(bool), this, onPlayPauseButtonPressed()); 41 | connect_(btnRepeat, clicked(bool), this, onRepeatButtonClicked(bool)); 42 | 43 | /* Slider*/ 44 | connect_(sliderAnimationTime, sliderMoved (int), this, onTimeSliderMoved(int)); 45 | 46 | /* Keyframes list */ 47 | connect_(lstKeyFrames, itemPressed(QListWidgetItem*), this, onItemClicked(QListWidgetItem*)); 48 | connect_(cloneAction, triggered(), this, onCloneKeyFramePressed()); 49 | connect_(changeTimeAction, triggered(), this, onKeyframeChangeTime()); 50 | connect_(deleteFramesAction, triggered(), this, onDeleteKeyframe()); 51 | connect_(loadKeyframe, triggered(), this, onLoadKeyframe()); 52 | 53 | /* Time edit */ 54 | timeEdit = new QLineEdit(lstKeyFrames); 55 | timeEdit->setInputMask("00:00.000"); 56 | timeEdit->setAlignment(Qt::AlignCenter); 57 | timeEdit->hide(); 58 | connect_(timeEdit, editingFinished (), this, onTimeTextFinished()); 59 | connect_(btnBackward, clicked(), this, onBackwardButtonPressed()); 60 | 61 | sliderAnimationTime->setMinimum(0); 62 | sliderAnimationTime->setTickPosition(QSlider::NoTicks); 63 | 64 | thumbnailRenderer = new OffScreenRenderer(NULL, NULL,128,128); 65 | } 66 | 67 | /******************************************************************************************************************************/ 68 | 69 | AnimationPanel::~AnimationPanel() 70 | { 71 | delete thumbnailRenderer; 72 | } 73 | 74 | /******************************************************************************************************************************/ 75 | /* EXTERNAL EVENTS */ 76 | /******************************************************************************************************************************/ 77 | 78 | void AnimationPanel::programStateUpdated(int flags) 79 | { 80 | if (!programstate) return; 81 | 82 | if (flags & ProgramState::KEYFRAME_LIST_EDITED) 83 | { 84 | /* See if one of our keyframes got updated 85 | * If so, update list items for it and all following keyframes */ 86 | int updated_index = programstate->getCurrentKeyframeId(); 87 | if (updated_index != -1) 88 | { 89 | updateItems(updated_index); 90 | updateTimeSlider(); 91 | } 92 | } 93 | 94 | if (flags & ProgramState::MODEL_EDITED ) 95 | { 96 | int updated_index = programstate->getCurrentKeyframeId(); 97 | updateListItem(updated_index); 98 | } 99 | 100 | if (flags & ProgramState::TEXTURE_CHANGED) 101 | { 102 | /* Texture changed - need to re-render everything */ 103 | thumbnailRenderer->setTexture(programstate->getTexture()); 104 | updateItems(0); 105 | } 106 | 107 | if ( flags & (ProgramState::ANIMATION_POSITION_CHANGED)) 108 | { 109 | sliderAnimationTime->setValue(programstate->getAnimationPosition()); 110 | int index = programstate->getCurrentKeyframeId(); 111 | selectFrame(index); 112 | } 113 | 114 | if (flags & ProgramState::MODE_CHANGED) 115 | { 116 | bool animation_running = programstate->getCurrentMode() == ProgramState::PROGRAM_MODE_ANIMATION_RUNNING; 117 | bool busy = programstate->isBusy() && !animation_running; 118 | 119 | lstKeyFrames->setDisabled(busy); 120 | sliderAnimationTime->setDisabled(busy); 121 | btnBackward->setDisabled(busy); 122 | btnAnimationPlay->setIcon(QIcon(animation_running ? ":/icons/pause.png" : ":/icons/play.png")); 123 | btnAnimationPlay->setEnabled(!busy); 124 | btnRepeat->setEnabled(!busy); 125 | } 126 | 127 | if (flags & ProgramState::CURRENT_MODEL_CHANGED) 128 | { 129 | sliderAnimationTime->setValue(programstate->getAnimationPosition()); 130 | /* See if one of our frames is selected - if so select it */ 131 | int newIndex = programstate->getCurrentKeyframeId(); 132 | if (newIndex != -1) 133 | selectFrame(newIndex); 134 | } 135 | } 136 | 137 | /******************************************************************************************************************************/ 138 | /* User input on our list */ 139 | /******************************************************************************************************************************/ 140 | 141 | void AnimationPanel::onItemClicked(QListWidgetItem *item) 142 | { 143 | if (!programstate) return; 144 | int newID = lstKeyFrames->row(item); 145 | selectFrame(newID); 146 | 147 | programstate->switchToKeyframe(newID); 148 | 149 | changeTimeAction->setEnabled(newID != 0); 150 | deleteFramesAction->setEnabled(programstate->getKeyframeCount() > 1); 151 | 152 | /* If we clicked on + sign, add new as a clone of last one */ 153 | if (newID == programstate->getKeyframeCount()) { 154 | programstate->cloneKeyframe(programstate->getKeyframeCount()-1); 155 | return; 156 | } 157 | 158 | } 159 | 160 | /******************************************************************************************************************************/ 161 | void AnimationPanel::onCloneKeyFramePressed() 162 | { 163 | if (!programstate) return; 164 | 165 | int currentID = programstate->getCurrentKeyframeId(); 166 | if (currentID == -1) return; 167 | programstate->cloneKeyframe(currentID); 168 | } 169 | 170 | /******************************************************************************************************************************/ 171 | void AnimationPanel::onDeleteKeyframe() 172 | { 173 | if (!programstate) return; 174 | 175 | /* Find what keyframe is selected - if none then its false call */ 176 | int currentID = programstate->getCurrentKeyframeId(); 177 | if (currentID == -1) return; 178 | programstate->deleteKeyFrame(currentID); 179 | } 180 | 181 | /******************************************************************************************************************************/ 182 | void AnimationPanel::onKeyframeChangeTime() 183 | { 184 | if (!programstate) return; 185 | 186 | int currentID = programstate->getCurrentKeyframeId(); 187 | if (currentID == -1 || currentID == 0) return; 188 | 189 | QRect r = lstKeyFrames->visualItemRect(lstKeyFrames->item(currentID)); 190 | 191 | int upstripe = (r.height() - 128)/2; 192 | 193 | r.setLeft(r.left()+10); 194 | r.setRight(r.right()-10); 195 | 196 | timeEdit->move(r.left(),r.bottom() - timeEdit->height()/2 - upstripe); 197 | timeEdit->resize(r.width(),timeEdit->height()); 198 | timeEdit->setText(QString::fromStdString(printTime(programstate->getKeyframeTime(currentID)))); 199 | timeEdit->show(); 200 | timeEdit->setFocus(); 201 | timeEdit->setCursorPosition(0); 202 | } 203 | 204 | /******************************************************************************************************************************/ 205 | void AnimationPanel::onTimeTextFinished() 206 | { 207 | timeEdit->hide(); 208 | if (!programstate) return; 209 | 210 | int newTime = getTime(timeEdit->text().toStdString()); 211 | 212 | if (newTime < 0) 213 | return; 214 | 215 | int currentID = programstate->getCurrentKeyframeId(); 216 | if (currentID == -1 || currentID == 0) return; 217 | 218 | int prevFrameTime = programstate->getKeyframeTime(currentID-1); 219 | programstate->setKeyframeTime(currentID-1,newTime-prevFrameTime); 220 | programstate->switchToKeyframe(currentID); 221 | } 222 | 223 | /******************************************************************************************************************************/ 224 | /* Time Slider */ 225 | /******************************************************************************************************************************/ 226 | 227 | void AnimationPanel::onPlayPauseButtonPressed() 228 | { 229 | if (!programstate) return; 230 | programstate->startStopAnimations(); 231 | } 232 | /******************************************************************************************************************************/ 233 | 234 | void AnimationPanel::onRepeatButtonClicked(bool checked) 235 | { 236 | if (!programstate) return; 237 | programstate->setAnimationRepeat(checked); 238 | } 239 | 240 | /******************************************************************************************************************************/ 241 | void AnimationPanel::onTimeSliderMoved(int newValue) 242 | { 243 | if (!programstate) return; 244 | programstate->setAnimationPosition(newValue); 245 | } 246 | 247 | /******************************************************************************************************************************/ 248 | /* Other */ 249 | /******************************************************************************************************************************/ 250 | void AnimationPanel::updateItems(int startItem) 251 | { 252 | if (!programstate) return; 253 | if (startItem == -1) return; 254 | 255 | int frameCount = programstate->getKeyframeCount(); 256 | for (int frame = startItem ; frame < frameCount ; frame++) 257 | updateListItem(frame); 258 | 259 | insertPlus(frameCount); 260 | int firstItemToRemove = frameCount + 1; 261 | 262 | while (lstKeyFrames->count() > firstItemToRemove) 263 | { 264 | QListWidgetItem* item = lstKeyFrames->takeItem(firstItemToRemove); 265 | delete item; 266 | } 267 | 268 | lstKeyFrames->repaint(); 269 | } 270 | 271 | /******************************************************************************************************************************/ 272 | void AnimationPanel::updateListItem(int id) 273 | { 274 | if (!programstate || !programstate->videoModel) return; 275 | 276 | VideoKeyFrame* frame = programstate->videoModel->getKeyframeByIndex(id); 277 | if (!frame) return; 278 | 279 | QListWidgetItem* item = lstKeyFrames->item(id); 280 | 281 | if (!item) { 282 | item = new QListWidgetItem; 283 | lstKeyFrames->insertItem(id,item); 284 | } 285 | 286 | /* This code is gross... yuck and I wrote it*/ 287 | QImage im; 288 | thumbnailRenderer->renderToQImage(frame, im,30,1); 289 | QPixmap p = QPixmap::fromImage(im); 290 | 291 | QPainter painter(&p); 292 | painter.drawText(im.rect(), Qt::AlignBottom | Qt::AlignCenter, 293 | QString::fromStdString(printTime(programstate->videoModel->getKeyFrameTimeMsec(frame)))); 294 | item->setIcon(QIcon(p)); 295 | } 296 | 297 | /******************************************************************************************************************************/ 298 | void AnimationPanel::insertPlus(int id) 299 | { 300 | QListWidgetItem* item = lstKeyFrames->item(id); 301 | 302 | if (!item) { 303 | item = new QListWidgetItem; 304 | lstKeyFrames->insertItem(id,item); 305 | } 306 | 307 | item->setIcon(plusIcon); 308 | } 309 | /******************************************************************************************************************************/ 310 | 311 | void AnimationPanel::selectFrame(int index) 312 | { 313 | lstKeyFrames->scrollToItem(lstKeyFrames->item(index+1)); 314 | lstKeyFrames->setCurrentRow(index); 315 | } 316 | 317 | /******************************************************************************************************************************/ 318 | void AnimationPanel::updateTimeSlider() 319 | { 320 | if (!programstate || !programstate->videoModel) return; 321 | 322 | int totalDuration = programstate->videoModel->getTotalTime(); 323 | int current_time = programstate->getKeyframeTime(programstate->getCurrentKeyframeId()); 324 | sliderAnimationTime->setMaximum(totalDuration); 325 | sliderAnimationTime->setValue(current_time); 326 | } 327 | 328 | /******************************************************************************************************************************/ 329 | void AnimationPanel::onShowHide(bool show) 330 | { 331 | setVisible(show); 332 | } 333 | /******************************************************************************************************************************/ 334 | 335 | void AnimationPanel::onBackwardButtonPressed() 336 | { 337 | if (!programstate) return; 338 | 339 | if (programstate->isAnimations()) 340 | programstate->setAnimationPosition(0); 341 | else 342 | programstate->switchToKeyframe(0); 343 | } 344 | 345 | /******************************************************************************************************************************/ 346 | 347 | void AnimationPanel::onLoadKeyframe() 348 | { 349 | QString filename = QFileDialog::getOpenFileName(this, tr("Choose model for the keyframe"), 350 | QString(), QLatin1String("*.obj *.off")); 351 | if (filename == NULL) 352 | return; 353 | 354 | programstate->loadKeyframe(filename.toStdString()); 355 | } 356 | -------------------------------------------------------------------------------- /GUI/AnimationPanel.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "ui_AnimationPanel.h" 9 | 10 | #include "ProgramState.h" 11 | 12 | class VideoModel; 13 | class KVFModel; 14 | class VideoKeyFrame; 15 | class MeshModel; 16 | class OffScreenRenderer; 17 | 18 | /*****************************************************************************************/ 19 | class AnimationPanel : public QDockWidget, public Ui_AnimationPanel 20 | { 21 | Q_OBJECT 22 | public: 23 | AnimationPanel(QWidget* parent); 24 | virtual ~AnimationPanel(); 25 | public slots: 26 | void programStateUpdated(int flags); 27 | void programStateCreated(ProgramState* state) { programstate = state; } 28 | 29 | /* Signals from list view*/ 30 | void onItemClicked(QListWidgetItem *item); 31 | void onCloneKeyFramePressed(); 32 | void onDeleteKeyframe(); 33 | void onKeyframeChangeTime(); 34 | void onTimeTextFinished(); 35 | void onTimeSliderMoved(int newValue); 36 | void onPlayPauseButtonPressed(); 37 | void onRepeatButtonClicked(bool checked); 38 | void onShowHide(bool show); 39 | void onBackwardButtonPressed(); 40 | void onLoadKeyframe(); 41 | private: 42 | void updateItems(int startItem); 43 | void updateListItem(int id); 44 | void updateTimeSlider(); 45 | 46 | void insertPlus(int id); 47 | void selectFrame(int index); 48 | private: 49 | QIcon plusIcon; 50 | QLineEdit *timeEdit; 51 | ProgramState* programstate; 52 | OffScreenRenderer *thumbnailRenderer; 53 | 54 | QAction *cloneAction; 55 | QAction *deleteFramesAction; 56 | QAction *changeTimeAction; 57 | QAction *loadKeyframe ; 58 | 59 | }; 60 | -------------------------------------------------------------------------------- /GUI/AnimationPanel.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AnimationPanel 4 | 5 | 6 | 7 | 0 8 | 0 9 | 549 10 | 223 11 | 12 | 13 | 14 | QDockWidget::DockWidgetClosable|QDockWidget::DockWidgetMovable 15 | 16 | 17 | Qt::BottomDockWidgetArea 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 4 26 | 27 | 28 | 2 29 | 30 | 31 | 2 32 | 33 | 34 | 6 35 | 36 | 37 | 2 38 | 39 | 40 | 41 | 42 | 0 43 | 44 | 45 | 46 | 47 | 48 | 0 49 | 0 50 | 51 | 52 | 53 | Press to start/stop the animations 54 | 55 | 56 | 57 | 58 | 59 | 60 | :/icons/play.png:/icons/play.png 61 | 62 | 63 | true 64 | 65 | 66 | 67 | 68 | 69 | 70 | Toggle loop mode (animation restarts when reaches end) 71 | 72 | 73 | 74 | 75 | 76 | 77 | :/icons/repeat.png:/icons/repeat.png 78 | 79 | 80 | true 81 | 82 | 83 | false 84 | 85 | 86 | 87 | 88 | 89 | 90 | Rewind animation to start 91 | 92 | 93 | 94 | 95 | 96 | 97 | :/icons/backward.png:/icons/backward.png 98 | 99 | 100 | 101 | 102 | 103 | 104 | Shows relative position of current frame to whole animation sequence 105 | 106 | 107 | Qt::Horizontal 108 | 109 | 110 | QSlider::TicksBelow 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 0 121 | 160 122 | 123 | 124 | 125 | true 126 | 127 | 128 | false 129 | 130 | 131 | false 132 | 133 | 134 | QAbstractItemView::DropOnly 135 | 136 | 137 | QAbstractItemView::SingleSelection 138 | 139 | 140 | 141 | 128 142 | 128 143 | 144 | 145 | 146 | QAbstractItemView::ScrollPerPixel 147 | 148 | 149 | QAbstractItemView::ScrollPerPixel 150 | 151 | 152 | QListView::Static 153 | 154 | 155 | QListView::LeftToRight 156 | 157 | 158 | false 159 | 160 | 161 | QListView::Adjust 162 | 163 | 164 | QListView::ListMode 165 | 166 | 167 | true 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | ActionButton 177 | QPushButton 178 |
ActionButton.h
179 |
180 |
181 | 182 | 183 | 184 | 185 |
186 | -------------------------------------------------------------------------------- /GUI/EditorWindow.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "EditorWindow.h" 10 | #include "MeshModel.h" 11 | #include "KVFModel.h" 12 | #include "OutlineModel.h" 13 | #include "VideoModel.h" 14 | #include 15 | 16 | /******************************************************************************************************************************/ 17 | EditorWindow::EditorWindow(QWidget* parent) : 18 | programstate(NULL), 19 | QGLWidget(QGLFormat(QGL::SampleBuffers), parent), 20 | textureRef(0) 21 | { 22 | setAttribute(Qt::WA_AcceptTouchEvents); 23 | setAttribute(Qt::WA_StaticContents); 24 | setFocusPolicy(Qt::WheelFocus); 25 | setMouseTracking(true); 26 | setContextMenuPolicy(Qt::ActionsContextMenu); 27 | } 28 | 29 | /******************************************************************************************************************************/ 30 | 31 | EditorWindow::~EditorWindow() 32 | { 33 | deleteTexture(textureRef); 34 | } 35 | 36 | /******************************************************************************************************************************/ 37 | 38 | void EditorWindow::programStateUpdated(int flags) 39 | { 40 | if (!programstate) return; 41 | MeshModel *currentModel = programstate->currentModel; 42 | bool need_repaint = false; 43 | 44 | if (flags & (ProgramState::CURRENT_MODEL_CHANGED)) 45 | { 46 | programstate->setSelectedVertexAndFace(-1,-1); 47 | need_repaint = true; 48 | } 49 | 50 | if (flags & (ProgramState::MODEL_EDITED | ProgramState::ANIMATION_POSITION_CHANGED)) { 51 | need_repaint = true; 52 | } 53 | 54 | if (flags & ProgramState::RENDER_SETTINGS_CHANGED) 55 | { 56 | setMouseTracking(programstate->getRenderSettings().showSelection); 57 | programstate->setSelectedVertexAndFace(-1,-1); 58 | need_repaint = true; 59 | } 60 | 61 | if (flags & ProgramState::TEXTURE_CHANGED) { 62 | makeCurrent(); 63 | deleteTexture(textureRef); 64 | textureRef = bindTexture(programstate->getTexture(),GL_TEXTURE_2D,GL_RGBA); 65 | need_repaint = true; 66 | } 67 | 68 | if (flags & ProgramState::TRANSFORM_RESET) { 69 | if (currentModel) { 70 | double maxZoomX = width() / currentModel->getWidth(); 71 | double maxZoomY = height() / currentModel->getHeight(); 72 | double maxZoom = std::min(maxZoomX,maxZoomY); 73 | modelWidth = currentModel->getWidth() * maxZoom * 0.5; 74 | modelLocation = QPointF(0, 0); 75 | need_repaint = true; 76 | } 77 | } 78 | 79 | if (need_repaint) 80 | repaint(); 81 | } 82 | 83 | /******************************************************************************************************************************/ 84 | 85 | void EditorWindow::initializeGL() 86 | { 87 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 88 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 89 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 90 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 91 | 92 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 93 | 94 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); 95 | glEnable(GL_LINE_SMOOTH); 96 | 97 | glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); 98 | glEnable(GL_POLYGON_SMOOTH); 99 | 100 | glEnable(GL_BLEND); 101 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 102 | } 103 | 104 | /******************************************************************************************************************************/ 105 | void EditorWindow::resizeGL(int w, int h) 106 | { 107 | repaint(); 108 | } 109 | 110 | /******************************************************************************************************************************/ 111 | 112 | void EditorWindow::paintGL() 113 | { 114 | glViewport(0,0,(GLint)width(), (GLint)height()); 115 | glClearColor(1.,1.,1., 1.0f); 116 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 117 | 118 | if (!programstate) return; 119 | MeshModel *renderModel = programstate->currentModel; 120 | const RenderSettings& editSettings = programstate->getRenderSettings(); 121 | 122 | if (!renderModel) 123 | return; 124 | 125 | TimeMeasurment t; 126 | 127 | double ratio = (renderModel->getWidth()) / modelWidth; 128 | 129 | double centerX = (-ratio * modelLocation.x()) + renderModel->center.x; 130 | double centerY = (-ratio * modelLocation.y()) + renderModel->center.y; 131 | double neededWidth = ratio * width(); 132 | double neededHeight = ratio * height(); 133 | 134 | /* Setup projection */ 135 | glMatrixMode(GL_PROJECTION); 136 | glLoadIdentity(); 137 | glOrtho(centerX - neededWidth/2 , centerX + neededWidth/2, centerY - neededHeight/2 , centerY + neededHeight/2, 0, 1); 138 | 139 | /* render the model*/ 140 | renderModel->renderFaces(); 141 | if (programstate->getRenderSettings().wireframeTransparency) 142 | { 143 | glColor4f(0,0,0,editSettings.wireframeTransparency); 144 | renderModel->renderWireframe(); 145 | } 146 | 147 | /* Some models will render stuff on top, like pined vertexes, extra wireframes, etc*/ 148 | renderModel->renderOverlay(ratio); 149 | 150 | 151 | /* Render hovered vertices */ 152 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 153 | if (programstate->getStatusbarData().selectedFace != -1) 154 | { 155 | glColor4f(0,0,1,0.5); 156 | renderModel->renderFace(programstate->getStatusbarData().selectedFace); 157 | } 158 | 159 | if (programstate->getStatusbarData().selectedVertex != -1) 160 | { 161 | glColor3f(0,0,1); 162 | renderModel->renderVertex(programstate->getStatusbarData().selectedVertex, ratio); 163 | } 164 | 165 | /* render selected vertices */ 166 | glColor3f(1,0,0); 167 | for (unsigned int i = 0; i < selectedVertices.size(); i++) 168 | renderModel->renderVertex(selectedVertices[i], ratio); 169 | 170 | 171 | /* render VF of KVF model */ 172 | KVFModel* kvfModel = dynamic_cast(renderModel); 173 | if (kvfModel) 174 | { 175 | if (editSettings.showVForig) 176 | kvfModel->renderVFOrig(); 177 | if (editSettings.showVF) 178 | kvfModel->renderVF(); 179 | } 180 | 181 | BDMORPHModel* bdmodel = dynamic_cast(renderModel); 182 | 183 | if (bdmodel) { 184 | if (editSettings.showBDmorphEdge) 185 | bdmodel->renderInitialEdge(ratio); 186 | 187 | if (editSettings.showBDmorphOrigMesh && bdmodel->modela ) { 188 | glColor4f(1,0,0,editSettings.wireframeTransparency); 189 | bdmodel->modela->renderWireframe(); 190 | } 191 | } 192 | 193 | printf("Editor: took %f msec to render\n",t.measure_msec()); 194 | } 195 | 196 | /******************************************************************************************************************************/ 197 | bool EditorWindow::event(QEvent *event) 198 | { 199 | switch (event->type()) { 200 | case QEvent::TouchBegin: 201 | case QEvent::TouchUpdate: 202 | case QEvent::TouchEnd: 203 | return touchEvent(static_cast(event)); 204 | default: 205 | return QWidget::event(event); 206 | } 207 | } 208 | 209 | /******************************************************************************************************************************/ 210 | bool EditorWindow::touchEvent(QTouchEvent* te) 211 | { 212 | if (!programstate) return false; 213 | if (programstate->getRenderSettings().pinMode) return false; 214 | if (!programstate->isDeformationEditor()) return false; 215 | 216 | KVFModel *kvfModel = dynamic_cast(programstate->currentModel); 217 | if (!kvfModel) return false; 218 | 219 | QList touchPoints = te->touchPoints(); 220 | 221 | #if 0 222 | if (!programstate->multitouchMode && touchPoints.count() == 2) 223 | { 224 | //zoom only in normal mode 225 | QTouchEvent::TouchPoint p0 = touchPoints.first(); 226 | QTouchEvent::TouchPoint p1 = touchPoints.last(); 227 | QLineF line1(p0.startPos(), p1.startPos()); 228 | QLineF line2(p0.pos(), p1.pos()); 229 | qreal scaleFactor = line2.length() / line1.length(); 230 | zoom(scaleFactor + (1 - scaleFactor) / 1.05); 231 | return true; 232 | } 233 | #endif 234 | 235 | if (te->type() == QEvent::TouchEnd) 236 | { 237 | touchPointLocations.clear(); 238 | selectedVertices.clear(); 239 | return true; 240 | } 241 | 242 | // fix set of pins 243 | std::set ids; 244 | 245 | for (int i = 0; i < touchPoints.size(); i++) 246 | { 247 | QTouchEvent::TouchPoint p = touchPoints[i]; 248 | if (touchPointLocations.count(p.id()) == 0) { 249 | touchPointLocations[p.id()] = p.pos(); 250 | touchToVertex[p.id()] = kvfModel->getClosestVertex(screenToModel(kvfModel,p.pos())); 251 | } 252 | ids.insert(p.id()); 253 | } 254 | 255 | std::map::iterator it = touchPointLocations.begin(); 256 | std::set toRemove; 257 | while (it != touchPointLocations.end()) { 258 | if (ids.count(it->first) == 0) 259 | toRemove.insert(it->first); 260 | ++it; 261 | } 262 | 263 | for (std::set::iterator iter = toRemove.begin();iter != toRemove.end(); ++iter) 264 | touchPointLocations.erase(*iter); 265 | 266 | // figure out if anything moved significantly 267 | double maxDistance = 0; 268 | 269 | for (int i = 0; i < touchPoints.size(); i++) 270 | { 271 | QPointF loc = touchPoints[i].pos(); 272 | QPointF old = touchPointLocations[touchPoints[i].id()]; 273 | QPointF diff = old - loc; 274 | double d = sqrt(diff.x() * diff.x() + diff.y() * diff.y()); 275 | if (d > maxDistance) 276 | maxDistance = d; 277 | } 278 | 279 | if (maxDistance >= 1) 280 | { 281 | // moved more than one pixel! 282 | std::set disps; 283 | 284 | for (int i = 0; i < touchPoints.size(); i++) 285 | { 286 | if (touchToVertex[touchPoints[i].id()] == -1) 287 | continue; 288 | 289 | Vector2 displacement = screenToModel(kvfModel,touchPoints[i].pos()) - 290 | screenToModel(kvfModel,touchPointLocations[touchPoints[i].id()]); 291 | 292 | disps.insert(DisplacedVertex(touchToVertex[touchPoints[i].id()], displacement)); 293 | touchPointLocations[touchPoints[i].id()] = touchPoints[i].pos(); 294 | } 295 | 296 | if (disps.size() > 0) 297 | { 298 | RenderSettings settings = programstate->getRenderSettings(); 299 | 300 | if (settings.showVF || settings.showVForig) 301 | kvfModel->calculateVF(disps,settings.alpha); 302 | else 303 | kvfModel->displaceMesh(disps,settings.alpha); 304 | 305 | programstate->informModelEdited(); 306 | programstate->setFPS(1000.0 / (kvfModel->lastVFApplyTime + kvfModel->lastVFCalcTime)); 307 | } 308 | } 309 | 310 | selectedVertices.clear(); 311 | for (std::map::iterator it = touchPointLocations.begin();it != touchPointLocations.end(); ++it) 312 | selectedVertices.push_back(touchToVertex[it->first]); 313 | 314 | return true; 315 | } 316 | /******************************************************************************************************************************/ 317 | void EditorWindow::keyPressEvent(QKeyEvent *e) 318 | { 319 | if (!programstate) return; 320 | 321 | switch(e->key()) { 322 | case Qt::Key_Up: 323 | moveUp(); 324 | repaint(); 325 | break; 326 | case Qt::Key_Down: 327 | moveDown(); 328 | repaint(); 329 | break; 330 | case Qt::Key_Left: 331 | moveLeft(); 332 | repaint(); 333 | break; 334 | case Qt::Key_Right: 335 | moveRight(); 336 | repaint(); 337 | break; 338 | case Qt::Key_Plus: 339 | case Qt::Key_Equal: 340 | zoomIn(); 341 | repaint(); 342 | break; 343 | case Qt::Key_Minus: 344 | case Qt::Key_Underscore: 345 | zoomOut(); 346 | repaint(); 347 | break; 348 | } 349 | } 350 | 351 | /******************************************************************************************************************************/ 352 | void EditorWindow::mousePressEvent(QMouseEvent *event) 353 | { 354 | mouseMoved = false; 355 | mouseLeft = event->buttons() & Qt::LeftButton; 356 | QPointF pos = event->pos(); // (0,0) is upper left 357 | pos.setY(height()-pos.y()-1); 358 | lastMousePos = pos; 359 | 360 | if (!programstate) return; 361 | MeshModel *model = programstate->currentModel; 362 | if (!model) return; 363 | 364 | setCursor(Qt::BlankCursor); 365 | Point2 modelPos = screenToModel(model,pos); 366 | 367 | if ((QApplication::keyboardModifiers() == Qt::NoModifier) && 368 | !programstate->getRenderSettings().pinMode && programstate->isDeformationEditor()) 369 | { 370 | Vertex v = model->getClosestVertex(modelPos); 371 | /* Select this vertex */ 372 | selectedVertices.clear(); 373 | selectedVertices.push_back(v); 374 | repaint(); 375 | return; 376 | } 377 | 378 | if (programstate->isBusy()) 379 | return; 380 | 381 | if (event->buttons() & Qt::LeftButton) 382 | model->mousePressAction(modelPos,getRadius(model)); 383 | 384 | repaint(); 385 | return; 386 | } 387 | /******************************************************************************************************************************/ 388 | void EditorWindow::mouseMoveEvent(QMouseEvent *event) 389 | { 390 | mouseLeft = event->buttons() & Qt::LeftButton; 391 | 392 | QPointF oldPos = lastMousePos; 393 | QPointF curPos = event->pos(); 394 | curPos.setY(height()-curPos.y()-1); 395 | 396 | if (lastMousePos == curPos) 397 | return; 398 | 399 | lastMousePos = curPos; 400 | 401 | if (!programstate) return; 402 | MeshModel *model = programstate->currentModel; 403 | KVFModel *kvfModel = dynamic_cast(programstate->currentModel); 404 | if (!model) return; 405 | 406 | Qt::KeyboardModifiers mods = QApplication::keyboardModifiers(); 407 | 408 | 409 | /* Plain mouse move */ 410 | if (event->buttons() == Qt::NoButton && programstate->getRenderSettings().showSelection && 411 | mods == Qt::NoModifier) 412 | { 413 | programstate->setSelectedVertexAndFace( 414 | model->getClosestVertex(screenToModel(model,curPos)), 415 | model->getFaceUnderPoint(screenToModel(model,curPos))); 416 | 417 | repaint(); 418 | return; 419 | } 420 | 421 | /* Right button pressed - always mouse move */ 422 | if ((event->buttons() & Qt::RightButton)) 423 | { 424 | QPointF diff = curPos - oldPos; 425 | move(QPointF(diff.x(),diff.y())); 426 | repaint(); 427 | mouseMoved = true; 428 | return; 429 | } 430 | 431 | /* Left button pressed - edit */ 432 | if ((event->buttons() & Qt::LeftButton)) 433 | { 434 | bool deformMode = 435 | programstate->isDeformationEditor() 436 | && kvfModel && !programstate->getRenderSettings().pinMode && !(mods & Qt::ShiftModifier); 437 | 438 | if (deformMode) 439 | { 440 | QPointF diff = curPos - oldPos; 441 | Vertex selectedVertex = selectedVertices[0]; 442 | diff *= kvfModel->getWidth() / modelWidth; 443 | if (diff.rx() == 0 && diff.ry() == 0) 444 | return; 445 | 446 | std::set disps; 447 | disps.insert(DisplacedVertex(selectedVertex, Vector2(diff.x(),diff.y()))); 448 | 449 | RenderSettings settings = programstate->getRenderSettings(); 450 | 451 | if (settings.showVF || settings.showVForig) 452 | kvfModel->calculateVF(disps,settings.alpha); 453 | else 454 | kvfModel->displaceMesh(disps,settings.alpha); 455 | 456 | programstate->informModelEdited(); 457 | programstate->setFPS(1000.0 / (kvfModel->lastVFCalcTime+kvfModel->lastVFApplyTime)); 458 | repaint(); 459 | return; 460 | } 461 | 462 | if (!model->moveAction(screenToModel(model,oldPos), screenToModel(model,curPos), getRadius(model))) 463 | return; 464 | mouseMoved = true; 465 | repaint(); 466 | } 467 | } 468 | 469 | /******************************************************************************************************************************/ 470 | void EditorWindow::mouseReleaseEvent(QMouseEvent *event) 471 | { 472 | setCursor(Qt::ArrowCursor); 473 | selectedVertices.clear(); 474 | 475 | if (!programstate) return; 476 | MeshModel *model = programstate->currentModel; 477 | if (!model) return; 478 | 479 | QPointF curPos = event->pos(); 480 | curPos.setY(height()-curPos.y()-1); 481 | 482 | model->mouseReleaseAction(screenToModel(model,curPos),mouseMoved, getRadius(model), !mouseLeft); 483 | model->historySnapshot(); 484 | 485 | update(); 486 | mouseMoved = false; 487 | } 488 | 489 | /******************************************************************************************************************************/ 490 | void EditorWindow::wheelEvent(QWheelEvent *event) 491 | { 492 | if (!programstate) return; 493 | MeshModel *model = programstate->currentModel; 494 | if (!model) return; 495 | 496 | QPointF pos = event->pos(); 497 | pos.setY(height()-pos.y()-1); 498 | 499 | Point2 posBefore = screenToModel(model,pos); 500 | zoom(event->delta() > 0 ? ZOOM_FACTOR : 1 / ZOOM_FACTOR); 501 | Point2 posAfter = screenToModel(model,pos); 502 | 503 | Vector2 diff = (posAfter-posBefore) * (modelWidth / model->getWidth()); 504 | QPointF m = QPointF(diff.x,diff.y); 505 | move(m); 506 | 507 | update(); 508 | } 509 | 510 | /******************************************************************************************************************************/ 511 | void EditorWindow::zoom(double factor) 512 | { 513 | modelWidth *= factor; 514 | } 515 | 516 | /******************************************************************************************************************************/ 517 | void EditorWindow::move(QPointF direction) 518 | { 519 | modelLocation += direction; 520 | } 521 | 522 | /******************************************************************************************************************************/ 523 | Point2 EditorWindow::screenToModel(MeshModel *model,QPointF pos) 524 | { 525 | assert(model); 526 | pos -= modelLocation; 527 | pos -= QPointF((double)width()/2,(double)height()/2); 528 | pos *= model->getWidth() / modelWidth; 529 | pos.rx() += model->center.x; 530 | pos.ry() += model->center.y; 531 | return Point2(pos.x(), pos.y()); 532 | } 533 | 534 | 535 | double EditorWindow::getRadius(MeshModel *model) 536 | { 537 | Point2 modelPos = screenToModel(model,QPointF(0,0)); 538 | Point2 modelPos2 = screenToModel(model,QPointF(0,5)); 539 | return modelPos.distance(modelPos2); 540 | } 541 | /******************************************************************************************************************************/ 542 | -------------------------------------------------------------------------------- /GUI/EditorWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFORMATIONSCENE_H 2 | #define DEFORMATIONSCENE_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "ProgramState.h" 10 | #include "vector2d.h" 11 | #include "utils.h" 12 | 13 | #define ZOOM_FACTOR 1.2 14 | 15 | class MeshModel; 16 | class KVFModel; 17 | class VideoModel; 18 | class OutlineModel; 19 | class ProgramState; 20 | 21 | class EditorWindow : public QGLWidget 22 | { 23 | Q_OBJECT 24 | public: 25 | EditorWindow(QWidget* parent); 26 | virtual ~EditorWindow(); 27 | 28 | public slots: 29 | void programStateUpdated(int flags); 30 | void programStateCreated(ProgramState* state) { programstate = state; } 31 | 32 | private: 33 | /* transformations*/ 34 | void zoom(double factor); 35 | void move(QPointF direction); 36 | void moveLeft() {move(QPointF(-10,0));} 37 | void moveRight() {move(QPointF(10,0));} 38 | void moveUp() {move(QPointF(0,10));} 39 | void moveDown() {move(QPointF(0,-10 ));} 40 | void zoomIn() {zoom(ZOOM_FACTOR);} 41 | void zoomOut() {zoom(1./ZOOM_FACTOR);} 42 | 43 | /* Events */ 44 | bool event(QEvent *); 45 | void mouseMoveEvent (QMouseEvent * event); 46 | void mousePressEvent ( QMouseEvent * event ); 47 | void mouseReleaseEvent(QMouseEvent * event); 48 | void wheelEvent (QWheelEvent * event ); 49 | void keyPressEvent ( QKeyEvent * event ); 50 | bool touchEvent(QTouchEvent* te); 51 | void paintGL(); 52 | void resizeGL(int w, int h); 53 | void initializeGL(); 54 | private: 55 | 56 | ProgramState* programstate; 57 | 58 | /* Model state */ 59 | QPointF modelLocation; 60 | double modelWidth; 61 | std::vector selectedVertices; 62 | 63 | /* Input state */ 64 | QPointF lastMousePos; 65 | std::map touchPointLocations; 66 | std::map touchToVertex; 67 | 68 | 69 | bool mouseMoved; 70 | bool mouseLeft; 71 | 72 | double getRadius(MeshModel *model); 73 | Point2 screenToModel(MeshModel *model, QPointF v); 74 | 75 | GLuint textureRef; 76 | 77 | }; 78 | #endif // DEFORMATIONSCENE_H 79 | -------------------------------------------------------------------------------- /GUI/Main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "MainWindow.h" 4 | #include "cholmod_common.h" 5 | #include "cholmod_matrix.h" 6 | #include 7 | 8 | 9 | #ifdef _WIN32 10 | int CALLBACK WinMain( 11 | _In_ HINSTANCE hInstance, 12 | _In_ HINSTANCE hPrevInstance, 13 | _In_ LPSTR lpCmdLine, 14 | _In_ int nCmdShow 15 | ) 16 | { 17 | int argc = 0; 18 | cholmod_initialize(); 19 | QApplication app(argc, NULL); 20 | MainWindow *window = new MainWindow(); 21 | window->show(); 22 | app.exec(); 23 | delete window; 24 | cholmod_finalize(); 25 | } 26 | #else 27 | int main(int argc, char **argv) 28 | { 29 | cholmod_initialize(); 30 | QApplication app(argc, argv); 31 | MainWindow *window = new MainWindow(); 32 | window->show(); 33 | app.exec(); 34 | delete window; 35 | cholmod_finalize(); 36 | } 37 | #endif 38 | -------------------------------------------------------------------------------- /GUI/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "MainWindow.h" 11 | #include "EditorWindow.h" 12 | #include "SidePanel.h" 13 | #include "AnimationPanel.h" 14 | #include "utils.h" 15 | #include "VideoModel.h" 16 | #include "BDMORPH.h" 17 | #include "OutlineModel.h" 18 | #include "ui_About.h" 19 | 20 | #include 21 | 22 | #ifdef _WIN32 23 | #include 24 | #endif 25 | 26 | /*****************************************************************************************************/ 27 | MainWindow::MainWindow() 28 | { 29 | setupUi(this); 30 | 31 | /* setup GL view */ 32 | editorWindow = new EditorWindow(this); 33 | setCentralWidget(editorWindow); 34 | 35 | /* setup side panel */ 36 | sidePanel = new SidePanel(this); 37 | addDockWidget(Qt::RightDockWidgetArea, sidePanel); 38 | 39 | /* setup animation panel */ 40 | animationPanel = new AnimationPanel(this); 41 | animationPanel->setTitleBarWidget(new QWidget(this)); 42 | addDockWidget(Qt::BottomDockWidgetArea, animationPanel); 43 | 44 | programstate = new ProgramState(); 45 | 46 | /* --------------------------------------------------------------------------------*/ 47 | /* Make everyone listen to program state */ 48 | connect_(programstate, programStateUpdated(int), editorWindow, programStateUpdated(int)); 49 | connect_(programstate, programStateUpdated(int), sidePanel, programStateUpdated(int)); 50 | connect_(programstate, programStateUpdated(int), animationPanel, programStateUpdated(int)); 51 | connect_(programstate, programStateUpdated(int), this, programStateUpdated(int)); 52 | 53 | editorWindow->programStateCreated(programstate); 54 | sidePanel->programStateCreated(programstate); 55 | animationPanel->programStateCreated(programstate); 56 | 57 | connect_(actionNew_model, triggered(), sidePanel, onImportProject()); 58 | connect_(actionLoad_mesh, triggered(), sidePanel, onLoadProject()); 59 | connect_(actionSave_model, triggered(), sidePanel, onSaveProject()); 60 | 61 | connect_(actionUndo, triggered(), sidePanel, onUndoModel()); 62 | connect_(actionRedo, triggered(), sidePanel, onRedoModel()); 63 | connect_(actionReset_model, triggered(), sidePanel, onResetPoints()); 64 | connect_(actionReset_pins, triggered(), sidePanel, onClearPins()); 65 | connect_(actionReplay_log, triggered(), sidePanel, onRunLog()); 66 | connect_(actionSave_log, triggered(), sidePanel, onSaveLog()); 67 | connect_(action_show_VF, toggled(bool), sidePanel, onDrawVFModeChanged(bool)); 68 | connect_(action_show_orig_VF, toggled(bool), sidePanel, onDrawOrigVFModeChanged(bool)); 69 | connect_(actionReapply_VF,triggered(), sidePanel, onReuseVF()); 70 | connect_(actionLoad_texture, triggered(), sidePanel, onChooseTexture()); 71 | connect_(actionReset_texture, triggered(), sidePanel, onResetTexture()); 72 | 73 | connect_(actionNew_keyframe, triggered(), animationPanel, onCloneKeyFramePressed()); 74 | connect_(actionDelete_keyframe, triggered(), animationPanel, onDeleteKeyframe()); 75 | connect_(actionPlay, triggered(), animationPanel, onPlayPauseButtonPressed()); 76 | 77 | connect_(actionSave_screenshot, triggered(), this, onSaveScreenShot()); 78 | connect_(actionSide_panel, toggled(bool), sidePanel, onShowHide(bool)); 79 | connect_(actionAnimation_panel, toggled(bool), animationPanel, onShowHide(bool)); 80 | connect_(actionAbout, triggered(), this, onAbout()); 81 | connect_(actionExit, triggered(), this, close()); 82 | connect_(actionTest_animations, triggered(), this, onInterpolationTest()); 83 | 84 | connect_(actionSave_video, triggered(), this, onSaveVideo()); 85 | connect_(actionDebug_Console, toggled(bool), this, onToggleDebugConsole(bool)); 86 | 87 | connect_(actionNew, triggered(), this, onNewProject()); 88 | 89 | /* --------------------------------------------------------------------------------*/ 90 | animationPanel->btnRepeat->setAction(actionLoop); 91 | sidePanel->chkPinMode->setAction(actionPin_edit_mode); 92 | actionSide_panel->setChecked(true); 93 | actionAnimation_panel->setChecked(true); 94 | 95 | /* setup statusbar*/ 96 | statusBar()->showMessage(tr("Ready")); 97 | 98 | lblMode = new QLabel(this); 99 | lblMode->setFrameStyle(QFrame::Panel | QFrame::Sunken); 100 | 101 | lblVertexCount = new QLabel(this); 102 | lblVertexCount->setFrameStyle(QFrame::Panel | QFrame::Sunken); 103 | 104 | lblFacesCount = new QLabel(this); 105 | lblFacesCount->setFrameStyle(QFrame::Panel | QFrame::Sunken); 106 | 107 | lblFPS = new QLabel(this); 108 | lblFPS->setFrameStyle(QFrame::Panel | QFrame::Sunken); 109 | 110 | lblSelectedFace = new QLabel(this); 111 | lblSelectedFace->setFrameStyle(QFrame::Panel | QFrame::Sunken); 112 | 113 | lblSelectedVertex = new QLabel(this); 114 | lblSelectedVertex->setFrameStyle(QFrame::Panel | QFrame::Sunken); 115 | 116 | progressIndicator = new QProgressBar; 117 | 118 | statusBar()->addPermanentWidget(lblFacesCount); 119 | statusBar()->addPermanentWidget(lblVertexCount); 120 | statusBar()->addPermanentWidget(lblSelectedVertex); 121 | statusBar()->addPermanentWidget(lblSelectedFace); 122 | statusBar()->addPermanentWidget(lblFPS); 123 | statusBar()->addPermanentWidget(lblMode); 124 | statusBar()->addPermanentWidget(progressIndicator); 125 | 126 | setContextMenuPolicy(Qt::NoContextMenu); 127 | 128 | lblMode->hide(); 129 | lblFPS->hide(); 130 | lblFacesCount->hide(); 131 | lblVertexCount->hide(); 132 | lblSelectedFace->hide(); 133 | lblSelectedVertex->hide(); 134 | progressIndicator->hide(); 135 | programstate->initialize(); 136 | } 137 | 138 | /*****************************************************************************************************/ 139 | MainWindow::~MainWindow() 140 | { 141 | delete editorWindow; 142 | delete animationPanel; 143 | delete sidePanel; 144 | delete programstate; 145 | } 146 | 147 | /*****************************************************************************************************/ 148 | void MainWindow::programStateUpdated(int flags) 149 | { 150 | QString str; 151 | if (flags & ProgramState::STATUSBAR_UPDATED) 152 | { 153 | StatusBarState state = programstate->getStatusbarData(); 154 | 155 | if (state.vertexCount > 0) 156 | { 157 | str.sprintf("Vertexes: %d", state.vertexCount); 158 | lblVertexCount->setText(str); 159 | lblVertexCount->show(); 160 | } else 161 | lblVertexCount->hide(); 162 | 163 | if (state.facesCount > 0) 164 | { 165 | str.sprintf("Faces: %d", state.facesCount); 166 | lblFacesCount->setText(str); 167 | lblFacesCount->show(); 168 | } else 169 | lblFacesCount->hide(); 170 | 171 | if (state.selectedFace >= 0) { 172 | lblSelectedFace->show(); 173 | str.sprintf("Face: %5d", state.selectedFace); 174 | lblSelectedFace->setText(str); 175 | } else 176 | lblSelectedFace->hide(); 177 | 178 | if (state.selectedVertex >= 0) { 179 | lblSelectedVertex->show(); 180 | str.sprintf("Vertex: %5d", state.selectedVertex); 181 | lblSelectedVertex->setText(str); 182 | } else 183 | lblSelectedVertex->hide(); 184 | 185 | if (state.FPS >=0 ) 186 | { 187 | str.sprintf("%06.2f FPS", state.FPS); 188 | lblFPS->setText(str); 189 | lblFPS->show(); 190 | } else { 191 | lblFPS->hide(); 192 | } 193 | 194 | if (state.progressValue != 0) { 195 | progressIndicator->setValue(state.progressValue); 196 | progressIndicator->show(); 197 | } else 198 | progressIndicator->hide(); 199 | 200 | if (state.statusbarMessage != "") 201 | statusBar()->showMessage(state.statusbarMessage); 202 | else 203 | statusBar()->showMessage("Ready"); 204 | } 205 | 206 | if (flags & ProgramState::MODE_CHANGED) 207 | { 208 | 209 | if (!programstate->isFullMode()) 210 | { 211 | animationPanel->setVisible(false); 212 | actionAnimation_panel->setEnabled(false); 213 | actionAnimation_panel->setChecked(false); 214 | 215 | } else if(actionAnimation_panel->isEnabled() == false) 216 | { 217 | animationPanel->setVisible(true); 218 | actionAnimation_panel->setEnabled(true); 219 | actionAnimation_panel->setChecked(true); 220 | } 221 | 222 | actionNew_keyframe->setEnabled(programstate->isDeformationEditor()); 223 | actionDelete_keyframe->setEnabled(programstate->isDeformationEditor()); 224 | actionReset_pins->setEnabled(programstate->isDeformationEditor()); 225 | actionPin_edit_mode->setEnabled(programstate->isDeformationEditor()); 226 | 227 | actionLoop->setEnabled(programstate->isFullMode() && (!programstate->isBusy() || programstate->isAnimations())); 228 | actionPlay->setEnabled(programstate->isFullMode() && (!programstate->isBusy() || programstate->isAnimations())); 229 | actionSave_video->setEnabled(programstate->isFullMode() && !programstate->isBusy()); 230 | 231 | actionNew->setEnabled(!programstate->isBusy()); 232 | actionNew_model->setEnabled(!programstate->isBusy()); 233 | actionLoad_mesh->setEnabled(!programstate->isBusy()); 234 | 235 | actionSave_model->setEnabled(!programstate->isBusy() && programstate->isModelLoaded()); 236 | actionLoad_texture->setEnabled(!programstate->isBusy() && programstate->isModelLoaded()); 237 | actionReset_texture->setEnabled(!programstate->isBusy() && programstate->isModelLoaded()); 238 | actionSave_screenshot->setEnabled(!programstate->isBusy() && programstate->isModelLoaded()); 239 | 240 | actionUndo->setEnabled(programstate->isEditing()); 241 | actionRedo->setEnabled(programstate->isEditing()); 242 | actionReset_model->setEnabled(programstate->isEditing()); 243 | 244 | actionReapply_VF->setEnabled(programstate->isDeformationEditor()); 245 | actionReplay_log->setEnabled(programstate->isDeformationEditor()); 246 | actionSave_log->setEnabled(programstate->isDeformationEditor()); 247 | 248 | action_show_VF->setEnabled(programstate->isDeformationEditor()); 249 | action_show_orig_VF->setEnabled(programstate->isDeformationEditor()); 250 | actionTest_animations->setEnabled(programstate->isFullMode()); 251 | 252 | switch (programstate->getCurrentMode()) { 253 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_ANIMATION_PAUSED: 254 | lblMode->show(); 255 | lblMode->setText("Interpolated frame"); 256 | break; 257 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_NONE: 258 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_BUSY: 259 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_ANIMATION_RUNNING: 260 | lblMode->hide(); 261 | break; 262 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_DEFORMATIONS: 263 | lblMode->show(); 264 | lblMode->setText("Keyframe"); 265 | break; 266 | case ProgramState::PROGRAM_MODE::PROGRAM_MODE_OUTLINE: 267 | lblMode->show(); 268 | lblMode->setText("Outline"); 269 | } 270 | 271 | 272 | } 273 | 274 | if (flags & ProgramState::PANEL_VISIBLITIY_CHANGED) { 275 | actionSide_panel->setChecked(sidePanel->isVisible()); 276 | } 277 | } 278 | /*****************************************************************************************************/ 279 | void MainWindow::onSaveScreenShot() 280 | { 281 | if ( !programstate) return; 282 | QString filename = QFileDialog::getSaveFileName(this, tr("Choose file"), QString(), QLatin1String("Image file (*.png *.jpg)")); 283 | if ( filename == "") return; 284 | programstate->saveScreenshot(filename.toStdString()); 285 | } 286 | 287 | /*****************************************************************************************************/ 288 | void MainWindow::onSaveVideo() 289 | { 290 | if ( !programstate) return; 291 | QString filename = QFileDialog::getSaveFileName(this, tr("Choose file"), QString(), QLatin1String("Video file (*.avi *.mp4)")); 292 | if ( filename == "") return; 293 | programstate->saveVideo(filename.toStdString()); 294 | } 295 | 296 | /*****************************************************************************************************/ 297 | 298 | void MainWindow::onAbout() 299 | { 300 | QDialog *dialog = new QDialog(this); 301 | Ui_aboutDialog t; 302 | t.setupUi(dialog); 303 | dialog->exec(); 304 | } 305 | 306 | /*****************************************************************************************************/ 307 | 308 | void MainWindow::onInterpolationTest() 309 | { 310 | programstate->setAnimationPosition(programstate->getAnimationPosition()+10); 311 | } 312 | 313 | /*****************************************************************************************************/ 314 | 315 | void MainWindow::onNewProject() 316 | { 317 | programstate->createProject(""); 318 | } 319 | 320 | /*****************************************************************************************************/ 321 | 322 | void MainWindow::onToggleDebugConsole(bool on) 323 | { 324 | #ifdef _WIN32 325 | 326 | // This shit is made exclusive for Windows(R) (TM) 327 | 328 | if (on) 329 | { 330 | // allocate a console for this app 331 | AllocConsole(); 332 | 333 | // redirect unbuffered STDOUT to the console 334 | HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); 335 | int fileDescriptor = _open_osfhandle((intptr_t)consoleHandle, _O_TEXT); 336 | FILE *fp = _fdopen( fileDescriptor, "w" ); 337 | *stdout = *fp; 338 | //setvbuf( stdout, NULL, _IONBF, 0 ); 339 | 340 | // give the console window a nicer title 341 | SetConsoleTitle("Debug Output"); 342 | 343 | // give the console window a bigger buffer size 344 | CONSOLE_SCREEN_BUFFER_INFO csbi; 345 | if ( GetConsoleScreenBufferInfo(consoleHandle, &csbi) ) 346 | { 347 | COORD bufferSize; 348 | bufferSize.X = csbi.dwSize.X; 349 | bufferSize.Y = 9999; 350 | SetConsoleScreenBufferSize(consoleHandle, bufferSize); 351 | } 352 | } 353 | else { 354 | FreeConsole(); 355 | } 356 | #endif 357 | } 358 | 359 | /*****************************************************************************************************/ 360 | -------------------------------------------------------------------------------- /GUI/MainWindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | 5 | #include 6 | #include 7 | #include "ui_MainWindow.h" 8 | #include "ProgramState.h" 9 | 10 | class SidePanel; 11 | class AnimationPanel; 12 | class EditorWindow; 13 | class OffScreenRenderer; 14 | class VideoModel; 15 | class MeshModel; 16 | class KVFModel; 17 | class QLabel; 18 | class BDMORPHModel; 19 | class OutlineModel; 20 | class QProgressBar; 21 | 22 | class MainWindow : public QMainWindow, public Ui_MainWindow 23 | { 24 | Q_OBJECT 25 | public: 26 | MainWindow(); 27 | virtual ~MainWindow(); 28 | public slots: 29 | void programStateUpdated(int flags); 30 | void onSaveScreenShot(); 31 | void onSaveVideo(); 32 | void onAbout(); 33 | void onInterpolationTest(); 34 | void onToggleDebugConsole(bool on); 35 | void onNewProject(); 36 | private: 37 | SidePanel* sidePanel; 38 | AnimationPanel* animationPanel; 39 | EditorWindow *editorWindow; 40 | 41 | QLabel* lblMode; 42 | QLabel* lblVertexCount; 43 | QLabel* lblFacesCount; 44 | QLabel* lblFPS; 45 | QLabel* lblSelectedVertex; 46 | QLabel* lblSelectedFace; 47 | 48 | QFrame *progressFrame; 49 | QProgressBar *progressIndicator; 50 | QPushButton *cancelButton; 51 | 52 | ProgramState* programstate; 53 | }; 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /GUI/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 968 10 | 733 11 | 12 | 13 | 14 | AKVF deformations with BDMORPH animation 15 | 16 | 17 | 18 | :/MainWindow/icon/icon.png:/MainWindow/icon/icon.png 19 | 20 | 21 | 22 | 23 | 5 24 | 25 | 26 | 5 27 | 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 0 35 | 968 36 | 23 37 | 38 | 39 | 40 | 41 | Project 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | View 58 | 59 | 60 | 61 | 62 | 63 | 64 | Edit 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Animations 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Debug 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | Help 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | Load... 114 | 115 | 116 | 117 | 118 | Load texture... 119 | 120 | 121 | 122 | 123 | Reset texture 124 | 125 | 126 | 127 | 128 | Reset 129 | 130 | 131 | 132 | 133 | Reset pins 134 | 135 | 136 | 137 | 138 | true 139 | 140 | 141 | Pin edit mode 142 | 143 | 144 | 145 | 146 | true 147 | 148 | 149 | Show dirichlet VF 150 | 151 | 152 | 153 | 154 | Undo 155 | 156 | 157 | Ctrl+Z 158 | 159 | 160 | 161 | 162 | Redo 163 | 164 | 165 | Ctrl+Shift+Z 166 | 167 | 168 | 169 | 170 | Save... 171 | 172 | 173 | 174 | 175 | Exit 176 | 177 | 178 | 179 | 180 | true 181 | 182 | 183 | Side panel 184 | 185 | 186 | 187 | 188 | true 189 | 190 | 191 | Animation panel 192 | 193 | 194 | 195 | 196 | New keyframe 197 | 198 | 199 | 200 | 201 | Play / Pause 202 | 203 | 204 | Space 205 | 206 | 207 | 208 | 209 | Export video... 210 | 211 | 212 | 213 | 214 | Delete keyframe 215 | 216 | 217 | 218 | 219 | Save log 220 | 221 | 222 | 223 | 224 | Replay log 225 | 226 | 227 | 228 | 229 | true 230 | 231 | 232 | Loop 233 | 234 | 235 | 236 | 237 | About 238 | 239 | 240 | 241 | 242 | Save screenshot... 243 | 244 | 245 | 246 | 247 | true 248 | 249 | 250 | Show VF 251 | 252 | 253 | 254 | 255 | Import... 256 | 257 | 258 | 259 | 260 | Test animations 261 | 262 | 263 | 264 | 265 | Reapply last VF 266 | 267 | 268 | V 269 | 270 | 271 | 272 | 273 | true 274 | 275 | 276 | Debug Console 277 | 278 | 279 | 280 | 281 | New 282 | 283 | 284 | Ctrl+N 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | -------------------------------------------------------------------------------- /GUI/OffScreenRenderer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include "OffScreenRenderer.h" 6 | #include "MeshModel.h" 7 | 8 | /*****************************************************************************************************/ 9 | OffScreenRenderer::OffScreenRenderer(QWidget* parent, QGLWidget* shareWidget, int width, int height) : 10 | QGLWidget(parent, shareWidget) , 11 | height(height), 12 | width(width) 13 | { 14 | makeCurrent(); 15 | fbo = new QGLFramebufferObject(width,height, QGLFramebufferObject::Depth,GL_TEXTURE_2D,GL_RGBA8 ); 16 | bool result = fbo->bind(); 17 | 18 | if (result == false) 19 | printf("Failed to bind thumbnail FBO\n"); 20 | 21 | textureRef = 0; 22 | 23 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 24 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 25 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 26 | glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 27 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 28 | glEnable(GL_TEXTURE_2D); 29 | glEnable(GL_BLEND); 30 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 31 | } 32 | /*****************************************************************************************************/ 33 | 34 | OffScreenRenderer::~OffScreenRenderer() 35 | { 36 | makeCurrent(); 37 | fbo->release(); 38 | deleteTexture(textureRef); 39 | delete fbo; 40 | } 41 | 42 | /*****************************************************************************************************/ 43 | 44 | void OffScreenRenderer::setTexture(const QPixmap &texture) 45 | { 46 | makeCurrent(); 47 | deleteTexture(textureRef); 48 | textureRef = bindTexture(texture,GL_TEXTURE_2D,GL_RGBA8); 49 | } 50 | 51 | /*****************************************************************************************************/ 52 | 53 | void OffScreenRenderer::renderToQImage(MeshModel* model, QImage &out, int stripeSize, double scale) 54 | { 55 | TimeMeasurment t; 56 | makeCurrent(); 57 | glClearColor(1.,1.,1., 1.0f); 58 | glClear(GL_COLOR_BUFFER_BIT); 59 | 60 | setupTransform(model,false,stripeSize,scale); 61 | 62 | model->renderFaces(); 63 | out = fbo->toImage(); 64 | printf("Offscreen renderer: took %f msec to render\n", t.measure_msec()); 65 | } 66 | 67 | /*****************************************************************************************************/ 68 | void OffScreenRenderer::renderToBufferBGRA(MeshModel* model, void* out) 69 | { 70 | TimeMeasurment t; 71 | makeCurrent(); 72 | glClearColor(1.,1.,1., 1.0f); 73 | glClear(GL_COLOR_BUFFER_BIT); 74 | model->renderFaces(); 75 | glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (GLvoid*)out); 76 | 77 | printf("Offscreen renderer: took %f msec to render to buffer\n", t.measure_msec()); 78 | } 79 | 80 | /*****************************************************************************************************/ 81 | void OffScreenRenderer::setupTransform(MeshModel* model,bool flip,int stripeSize,double scale) 82 | { 83 | int height1 = height - stripeSize; 84 | makeCurrent(); 85 | 86 | glViewport(0,stripeSize,width, height - stripeSize); 87 | 88 | BBOX b = model->getActualBBox(); 89 | 90 | double ratio = std::max(b.width() / width, b.height() / height1) / scale; 91 | double neededWidth = ratio * width; 92 | double neededHeight = ratio * height1; 93 | 94 | /* Setup projection */ 95 | glMatrixMode(GL_PROJECTION); 96 | glLoadIdentity(); 97 | 98 | if (flip) 99 | neededHeight *= -1; 100 | 101 | glOrtho(b.center().x - neededWidth/2 , b.center().x + neededWidth/2, b.center().y - neededHeight/2 , 102 | b.center().y + neededHeight/2, 0, 1); 103 | 104 | } 105 | 106 | /*****************************************************************************************************/ 107 | -------------------------------------------------------------------------------- /GUI/OffScreenRenderer.h: -------------------------------------------------------------------------------- 1 | #ifndef THUMBNAILRENDERER_H_ 2 | #define THUMBNAILRENDERER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class MeshModel; 10 | class OffScreenRenderer : public QGLWidget 11 | { 12 | Q_OBJECT 13 | public: 14 | OffScreenRenderer(QWidget* parent, QGLWidget* shareWidget, int width,int height); 15 | virtual ~OffScreenRenderer(); 16 | 17 | /* Set texture used for rendering */ 18 | void setTexture(const QPixmap &texture); 19 | 20 | /* Slow simple render */ 21 | void renderToQImage(MeshModel* model, QImage& out, int stripSize, double scale); 22 | 23 | /* Fast render for video */ 24 | void setupTransform(MeshModel* model,bool vertFlip,int stripSize, double scale); 25 | void renderToBufferBGRA(MeshModel* model, void* out); 26 | 27 | 28 | private: 29 | int width; 30 | int height; 31 | QGLFramebufferObject *fbo; 32 | GLuint textureRef; 33 | }; 34 | 35 | #endif /* THUMBNAILRENDERER_H_ */ 36 | -------------------------------------------------------------------------------- /GUI/ProgramState.h: -------------------------------------------------------------------------------- 1 | #ifndef PROGRAMSTATE_H_ 2 | #define PROGRAMSTATE_H_ 3 | 4 | #include "VideoModel.h" 5 | #include "OutlineModel.h" 6 | #include "ffmpeg_encoder.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | struct StatusBarState { 14 | double FPS; 15 | int vertexCount; 16 | int facesCount; 17 | int progressValue; 18 | int selectedVertex; 19 | int selectedFace; 20 | QString statusbarMessage; 21 | }; 22 | 23 | struct RenderSettings 24 | { 25 | /* KVF render settings */ 26 | bool showVF; 27 | bool showVForig; 28 | bool showSelection; 29 | double wireframeTransparency; 30 | 31 | /* bdmorph settings*/ 32 | bool showBDmorphEdge; 33 | bool showBDmorphOrigMesh; 34 | int targetFPS; 35 | 36 | bool pinMode; 37 | double alpha; 38 | 39 | std::string textureFile; 40 | QPixmap texture; 41 | 42 | }; 43 | 44 | 45 | class ProgramState: public QObject 46 | { 47 | Q_OBJECT 48 | public: 49 | ProgramState(); 50 | virtual ~ProgramState(); 51 | 52 | enum PROGRAM_MODE 53 | { 54 | PROGRAM_MODE_NONE, 55 | 56 | /* outline editor */ 57 | PROGRAM_MODE_OUTLINE, 58 | 59 | /* use KVF to edit current frame */ 60 | PROGRAM_MODE_DEFORMATIONS, 61 | 62 | /* animation running or paused */ 63 | PROGRAM_MODE_ANIMATION_PAUSED, 64 | PROGRAM_MODE_ANIMATION_RUNNING, 65 | 66 | /* busy (saving video or replaying log or whatever)*/ 67 | PROGRAM_MODE_BUSY, 68 | }; 69 | 70 | /* Models */ 71 | MeshModel *currentModel; 72 | VideoModel *videoModel; 73 | OutlineModel *outlineModel; 74 | 75 | /* current mode management */ 76 | void setCurrentMode(enum PROGRAM_MODE mode); 77 | 78 | enum PROGRAM_MODE getCurrentMode(); 79 | 80 | /* is some model loaded*/ 81 | bool isModelLoaded() { return mode != PROGRAM_MODE_NONE; } 82 | 83 | /* are we in busy state where most of GUI should be disabled? 84 | * (animation is running, or we are saving to file or we are replaying the log) 85 | */ 86 | bool isBusy() { return mode == PROGRAM_MODE_ANIMATION_RUNNING || mode == PROGRAM_MODE_BUSY; } 87 | 88 | /* do we edit something ?*/ 89 | bool isOutlineEditor() { return mode == PROGRAM_MODE_OUTLINE; } 90 | bool isDeformationEditor() { return mode == PROGRAM_MODE_DEFORMATIONS; } 91 | bool isEditing() { return isOutlineEditor() || isDeformationEditor(); } 92 | 93 | /* do we show animations*/ 94 | bool isAnimations() { return mode == PROGRAM_MODE_ANIMATION_RUNNING || mode == PROGRAM_MODE_ANIMATION_PAUSED; } 95 | 96 | /* Are we in full edit mode ( as opposed to noting or outline)*/ 97 | bool isFullMode() { return mode != PROGRAM_MODE_OUTLINE && mode != PROGRAM_MODE_NONE; } 98 | 99 | 100 | /* render setting management */ 101 | void setRenderSettings(const RenderSettings &newsettings); 102 | const RenderSettings& getRenderSettings() { return renderSettings;}; 103 | const QPixmap& getTexture() const { return renderSettings.texture; } 104 | void resetTransform(); 105 | 106 | /* editor calls this to inform that current model got updated */ 107 | void informModelEdited(); 108 | void updateGUI(); 109 | 110 | /* statusbar */ 111 | void setSelectedVertexAndFace(int selectedVertex, int selectedFace); 112 | void setFPS(double newFPS); 113 | void showStatusBarMessage(const QString& message); 114 | void setProgress(int value); 115 | StatusBarState getStatusbarData() { return statusbarState; } 116 | 117 | 118 | void runLog(std::string filename); 119 | void saveLog(std::string filename); 120 | 121 | public: 122 | void initialize(); 123 | 124 | /* Load/store parts of the state */ 125 | bool createProject(std::string file); 126 | bool loadProject(std::string filename); 127 | bool saveToFile(std::string filename); 128 | bool saveScreenshot(std::string filename); 129 | bool saveVideo(std::string file); 130 | bool createProjectFromOutline(int triangleCount); 131 | void editOutline(); 132 | void autoCreateOutline(); 133 | bool loadTexture(std::string textureFile); 134 | bool loadKeyframe(std::string file); 135 | 136 | /* Animation panel uses this to edit list of keyframes*/ 137 | void switchToKeyframe(int newIndex); 138 | void cloneKeyframe(int id = -1); 139 | void deleteKeyFrame(int id = -1); 140 | void setKeyframeTime(int id, int newTime); 141 | void createKeyframeFromPFrame(); 142 | 143 | /* Gets information on keyframes*/ 144 | int getCurrentKeyframeId(); 145 | int getKeyframeCount(); 146 | int getKeyframeTime(int id); 147 | 148 | /* Animations controls */ 149 | void startStopAnimations(); 150 | void setAnimationRepeat(bool enabled); 151 | 152 | /* Calculate and show on screen an interpolated frame */ 153 | int getAnimationPosition() { return currentAnimationTime; } 154 | void setAnimationPosition(int newPosition); 155 | 156 | enum UPDATE_FLAGS 157 | { 158 | /* Mode of operation (outline/kvf/pframe/video) got changed */ 159 | MODE_CHANGED = 0x1, 160 | 161 | /* new keyframe created/keyframe deleted/keyframe got time change */ 162 | KEYFRAME_LIST_EDITED = 0x2, 163 | 164 | /* currentModel is now different model */ 165 | CURRENT_MODEL_CHANGED = 0x4, 166 | 167 | /* current model is the same but it got edited (used changed the points using KVF) */ 168 | MODEL_EDITED = 0x8, 169 | 170 | /* New animation frame was interpolated */ 171 | ANIMATION_POSITION_CHANGED = 0x10, 172 | 173 | /* Settings actuall for edit window got changed */ 174 | RENDER_SETTINGS_CHANGED = 0x20, 175 | 176 | /* textureref got changed (this is also part of render settings actually) */ 177 | TEXTURE_CHANGED = 0x40, 178 | 179 | /* Information in the state to be displayed on statusbar got changed */ 180 | STATUSBAR_UPDATED = 0x80, 181 | 182 | /* Request for scale/move reset */ 183 | TRANSFORM_RESET = 0x100, 184 | 185 | PANEL_VISIBLITIY_CHANGED = 0x200, 186 | }; 187 | 188 | signals: 189 | /* Informs all the users that parts of the state changed */ 190 | void programStateUpdated(int flags); 191 | private slots: 192 | void onAnimationTimer(); 193 | private: 194 | void clearStatusBar(); 195 | void unloadAll(); 196 | void unloadVideoModel(); 197 | void unloadOutlineModel(); 198 | bool loadTextureFile(std::string file, QPixmap &out); 199 | void updateTexture(); 200 | void tryToGuessLoadTexture(std::string file); 201 | void interpolateFrame(int time); 202 | 203 | 204 | /* Current program mode */ 205 | ProgramState::PROGRAM_MODE mode; 206 | 207 | /* Animation settings */ 208 | int currentAnimationTime; 209 | bool animationRepeat; 210 | QTimer *animationTimer; 211 | QElapsedTimer animationReferenceTimer; 212 | int maxAnimationTime; 213 | 214 | /* Render settings*/ 215 | RenderSettings renderSettings; 216 | 217 | /* Statusbar settings */ 218 | StatusBarState statusbarState; 219 | }; 220 | #endif /* PROGRAMSTATE_H_ */ 221 | -------------------------------------------------------------------------------- /GUI/SidePanel.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "SidePanel.h" 4 | #include "KVFModel.h" 5 | #include "BDMORPH.h" 6 | #include "OutlineModel.h" 7 | #include "utils.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | SidePanel::SidePanel(QWidget* parent) : QDockWidget(parent), programstate(NULL) 14 | { 15 | setupUi(this); 16 | connect_(btnCreateMesh, clicked(), this, onMeshCreateButtonPressed()); 17 | connect_(btnResetMesh, clicked(), this, onResetPoints()); 18 | connect_(btnResetPins, clicked(), this, onClearPins()); 19 | connect_(btnResetTransform, clicked(), this, onResetTransform()); 20 | connect_(btnUndo, clicked(), this, onUndoModel()); 21 | connect_(btnRedo, clicked(), this, onRedoModel()); 22 | connect_(chkPinMode, clicked(bool), this, onPinModeChanged(bool)); 23 | connect_(chkShowSelection, clicked(bool), this, onShowSelectionChanged(bool)); 24 | connect_(sliderWireframeTransparency, valueChanged(int), this, onChangeWireframe(int)); 25 | connect_(sliderAlpha, valueChanged(int), this, onChangeAlpha(int)); 26 | 27 | connect_(btnNewModel, clicked(), this, onImportProject()); 28 | connect_(btnLoadModel, clicked(), this, onLoadProject()); 29 | connect_(btnSaveModel, clicked(), this, onSaveProject()); 30 | connect_(btnResetTexture, clicked(), this, onResetTexture()); 31 | connect_(btnLoadTexture, clicked(), this, onChooseTexture()); 32 | connect_(btnEditOutline, clicked(), this, onEditOutlinePressed()); 33 | 34 | connect_(chkShowStartModel, clicked(bool), this, onBdmorphOrigModel(bool)); 35 | connect_(chkShowAnchorEdge, clicked(bool), this, onShowBdmorphEdgeClicked(bool)); 36 | 37 | connect_(btnConvertToKeyframe, clicked(), this, onBdmorphConvertToKeyframe()); 38 | connect_(spinFPSBox, valueChanged (int), this, onTargetFPSChanged(int)); 39 | connect_(btnCreateOutline, clicked(), this, onAutoOutlineCreate()); 40 | 41 | sliderMeshDensity->setRange(0,100000); 42 | sliderMeshDensity->setTickPosition(QSlider::NoTicks); 43 | sliderMeshDensity->setSliderPosition(1000); 44 | sliderAlpha->setValue(5); 45 | sliderAlpha->setMaximum(10000); 46 | sliderAlpha->setMinimum(0); 47 | sliderAlpha->setTickPosition(QSlider::NoTicks); /* I don't want ticks, these are awful I heard*/ 48 | } 49 | 50 | /******************************************************************************************************************************/ 51 | void SidePanel::programStateUpdated(int flags) 52 | { 53 | if (flags & ProgramState::ANIMATION_POSITION_CHANGED) 54 | { 55 | QString bdmorphTime; 56 | bdmorphTime.sprintf("Current time: %s (t = %f)", 57 | printTime(programstate->getAnimationPosition()).c_str(), 58 | programstate->videoModel->pFrame->current_t); 59 | 60 | lblCurrentBDMORPHTime->setText(bdmorphTime); 61 | } 62 | 63 | if (flags & ProgramState::MODE_CHANGED) 64 | { 65 | bool animations_paused = programstate->getCurrentMode() == ProgramState::PROGRAM_MODE_ANIMATION_PAUSED; 66 | 67 | frameOutline->setVisible(false); 68 | frameKVF->setVisible(false); 69 | frameBDMorph->setVisible(false); 70 | frameEdit->setVisible(false); 71 | frameWireframe->setVisible(false); 72 | 73 | frameLoad->setEnabled(!programstate->isBusy()); 74 | btnLoadTexture->setEnabled(programstate->isModelLoaded()); 75 | btnResetTexture->setEnabled(programstate->isModelLoaded()); 76 | btnSaveModel->setEnabled(programstate->isModelLoaded()); 77 | 78 | btnConvertToKeyframe->setEnabled(animations_paused); 79 | frameOutline->setVisible(programstate->isOutlineEditor()); 80 | frameKVF->setVisible(programstate->isDeformationEditor()); 81 | frameBDMorph->setVisible(programstate->isAnimations()); 82 | frameEdit->setVisible(programstate->isEditing()); 83 | frameWireframe->setVisible(programstate->isFullMode()); 84 | btnEditOutline->setEnabled(programstate->isFullMode()); 85 | btnCreateMesh->setEnabled(!programstate->isFullMode()); 86 | 87 | } 88 | 89 | if (flags & (ProgramState::RENDER_SETTINGS_CHANGED|ProgramState::CURRENT_MODEL_CHANGED)) 90 | { 91 | KVFModel *kvfModel = dynamic_cast(programstate->currentModel); 92 | RenderSettings settings = programstate->getRenderSettings(); 93 | 94 | if (kvfModel) { 95 | sliderAlpha->setValue(settings.alpha * 1000); 96 | QString alphaLabel; 97 | alphaLabel.sprintf("Control points weight: (alpha=%f)", settings.alpha ); 98 | lblControlPoints->setText(alphaLabel); 99 | } 100 | sliderWireframeTransparency->setValue(settings.wireframeTransparency*100); 101 | } 102 | } 103 | 104 | /******************************************************************************************************************************/ 105 | void SidePanel::onImportProject() 106 | { 107 | QString filename = QFileDialog::getOpenFileName(this, tr("Choose base for new model (picture/outline/mesh"), 108 | QString(), QLatin1String("Mesh (*.obj *.off);;Picture (*.png *.jpg);;Outline (*.poly)")); 109 | if (filename == NULL) 110 | return; 111 | programstate->createProject(filename.toStdString()); 112 | } 113 | 114 | /*****************************************************************************************************/ 115 | void SidePanel::onLoadProject() 116 | { 117 | QString filename = QFileDialog::getOpenFileName(this, tr("Choose video model to load"), 118 | QString(), QLatin1String("*.vproject")); 119 | if (filename == "") return; 120 | programstate->loadProject(filename.toStdString()); 121 | } 122 | 123 | /*****************************************************************************************************/ 124 | void SidePanel::onSaveProject() 125 | { 126 | if ( !programstate) return; 127 | 128 | QString outputFormat; 129 | 130 | if (programstate->videoModel) 131 | outputFormat = "Video Project (*.vproject);;Mesh (*.obj)"; 132 | 133 | else if (programstate->outlineModel) 134 | outputFormat="Outline (*.poly)"; 135 | 136 | QString filename = QFileDialog::getSaveFileName(this, tr("Choose file"), QString(), outputFormat); 137 | if ( filename == "") return; 138 | 139 | programstate->saveToFile(filename.toStdString()); 140 | } 141 | 142 | /*****************************************************************************************************/ 143 | void SidePanel::onChooseTexture() 144 | { 145 | QString filename = QFileDialog::getOpenFileName(this, tr("Choose image"), QString(), QString("Texture (*.png *.jpg *.bmp)")); 146 | if (filename == NULL) 147 | return; 148 | 149 | programstate->loadTexture(filename.toStdString()); 150 | } 151 | 152 | /*****************************************************************************************************/ 153 | void SidePanel::onResetTexture() 154 | { 155 | programstate->loadTexture(""); 156 | } 157 | 158 | /*****************************************************************************************************/ 159 | void SidePanel::onMeshCreateButtonPressed() 160 | { 161 | int density = sliderMeshDensity->value(); 162 | programstate->createProjectFromOutline(density); 163 | } 164 | 165 | /******************************************************************************************************************************/ 166 | 167 | void SidePanel::onEditOutlinePressed() 168 | { 169 | programstate->editOutline(); 170 | } 171 | 172 | /******************************************************************************************************************************/ 173 | void SidePanel::onResetPoints() 174 | { 175 | if (!programstate) return; 176 | MeshModel *model = programstate->currentModel; 177 | if (!model) return; 178 | model->historyReset(); 179 | programstate->informModelEdited(); 180 | } 181 | /******************************************************************************************************************************/ 182 | void SidePanel::onUndoModel() 183 | { 184 | if (!programstate) return; 185 | MeshModel *model = programstate->currentModel; 186 | if (!model) return; 187 | model->historyUndo(); 188 | programstate->informModelEdited(); 189 | } 190 | 191 | /******************************************************************************************************************************/ 192 | void SidePanel::onRedoModel() 193 | { 194 | if (!programstate) return; 195 | MeshModel *model = programstate->currentModel; 196 | if (!model) return; 197 | model->historyRedo(); 198 | programstate->informModelEdited(); 199 | } 200 | 201 | /******************************************************************************************************************************/ 202 | void SidePanel::onSaveLog() 203 | { 204 | if (!programstate) return; 205 | QString filename = QFileDialog::getSaveFileName(this, tr("Choose file"), QString(), QLatin1String("*.txt")); 206 | if (filename == "") return; 207 | programstate->saveLog(filename.toStdString()); 208 | } 209 | 210 | /******************************************************************************************************************************/ 211 | void SidePanel::onRunLog() 212 | { 213 | if (!programstate) return; 214 | QString filename = QFileDialog::getOpenFileName(this, tr("Choose log"), QString(), QLatin1String("*.txt")); 215 | if (filename == "") return; 216 | programstate->runLog(filename.toStdString()); 217 | } 218 | /******************************************************************************************************************************/ 219 | 220 | void SidePanel::onClearPins() 221 | { 222 | if (!programstate) return; 223 | KVFModel *kvfModel = dynamic_cast(programstate->currentModel); 224 | if (!kvfModel) return; 225 | kvfModel->clearPins(); 226 | programstate->informModelEdited(); 227 | } 228 | 229 | /******************************************************************************************************************************/ 230 | void SidePanel::onReuseVF() 231 | { 232 | if (!programstate) return; 233 | KVFModel *kvfModel = dynamic_cast(programstate->currentModel); 234 | if (!kvfModel) return; 235 | kvfModel->applyVF(); 236 | programstate->informModelEdited(); 237 | } 238 | 239 | /******************************************************************************************************************************/ 240 | void SidePanel::onChangeAlpha(int i) 241 | { 242 | if (!programstate) return; 243 | RenderSettings settings = programstate->getRenderSettings(); 244 | settings.alpha = (((double) (i)) / 1000); 245 | programstate->setRenderSettings(settings); 246 | } 247 | 248 | /******************************************************************************************************************************/ 249 | void SidePanel::onDrawVFModeChanged(bool m) 250 | { 251 | if (!programstate) return; 252 | RenderSettings settings = programstate->getRenderSettings(); 253 | settings.showVF = m; 254 | programstate->setRenderSettings(settings); 255 | } 256 | 257 | /******************************************************************************************************************************/ 258 | void SidePanel::onDrawOrigVFModeChanged(bool m) 259 | { 260 | if (!programstate) return; 261 | RenderSettings settings = programstate->getRenderSettings(); 262 | settings.showVForig = m; 263 | programstate->setRenderSettings(settings); 264 | } 265 | 266 | /******************************************************************************************************************************/ 267 | 268 | void SidePanel::onShowSelectionChanged(bool m) 269 | { 270 | if (!programstate) return; 271 | RenderSettings settings = programstate->getRenderSettings(); 272 | settings.showSelection = m; 273 | programstate->setRenderSettings(settings); 274 | } 275 | 276 | /******************************************************************************************************************************/ 277 | void SidePanel::onPinModeChanged(bool m) 278 | { 279 | if (!programstate) return; 280 | RenderSettings settings = programstate->getRenderSettings(); 281 | settings.pinMode = m; 282 | programstate->setRenderSettings(settings); 283 | } 284 | /******************************************************************************************************************************/ 285 | void SidePanel::onChangeWireframe(int i) 286 | { 287 | if (!programstate) return; 288 | RenderSettings settings = programstate->getRenderSettings(); 289 | settings.wireframeTransparency = (double)i / 100.0; 290 | programstate->setRenderSettings(settings); 291 | } 292 | 293 | /******************************************************************************************************************************/ 294 | void SidePanel::onShowBdmorphEdgeClicked(bool checked) 295 | { 296 | if (!programstate) return; 297 | RenderSettings settings = programstate->getRenderSettings(); 298 | settings.showBDmorphEdge = checked; 299 | programstate->setRenderSettings(settings); 300 | } 301 | 302 | 303 | /******************************************************************************************************************************/ 304 | void SidePanel::onBdmorphOrigModel(bool checked) 305 | { 306 | if (!programstate) return; 307 | RenderSettings settings = programstate->getRenderSettings(); 308 | settings.showBDmorphOrigMesh = checked; 309 | programstate->setRenderSettings(settings); 310 | } 311 | 312 | 313 | /******************************************************************************************************************************/ 314 | void SidePanel::onResetTransform() 315 | { 316 | if (!programstate) return; 317 | programstate->resetTransform(); 318 | } 319 | 320 | /******************************************************************************************************************************/ 321 | 322 | void SidePanel::onShowHide(bool checked) 323 | { 324 | setVisible(checked); 325 | } 326 | 327 | /******************************************************************************************************************************/ 328 | void SidePanel::onBdmorphConvertToKeyframe() 329 | { 330 | programstate->createKeyframeFromPFrame(); 331 | } 332 | 333 | /******************************************************************************************************************************/ 334 | void SidePanel::onTargetFPSChanged(int newValue) 335 | { 336 | RenderSettings settings = programstate->getRenderSettings(); 337 | settings.targetFPS = newValue; 338 | programstate->setRenderSettings(settings); 339 | } 340 | 341 | /******************************************************************************************************************************/ 342 | void SidePanel::closeEvent (QCloseEvent *event) 343 | { 344 | hide(); 345 | programstate->updateGUI(); 346 | } 347 | /******************************************************************************************************************************/ 348 | void SidePanel::onAutoOutlineCreate() 349 | { 350 | programstate->autoCreateOutline(); 351 | } 352 | -------------------------------------------------------------------------------- /GUI/SidePanel.h: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "ui_SidePanel.h" 4 | #include "ProgramState.h" 5 | class MeshModel; 6 | class VideoModel; 7 | 8 | class SidePanel : public QDockWidget, public Ui_sidePanel 9 | { 10 | Q_OBJECT 11 | public: 12 | SidePanel(QWidget* parent); 13 | void programStateCreated(ProgramState* state) { programstate = state; } 14 | 15 | public slots: 16 | void programStateUpdated(int flags); 17 | void onShowHide(bool show); 18 | 19 | void onImportProject(); 20 | void onLoadProject(); 21 | void onSaveProject(); 22 | void onChooseTexture(); 23 | void onResetTexture(); 24 | void onMeshCreateButtonPressed(); 25 | void onEditOutlinePressed(); 26 | void onAutoOutlineCreate(); 27 | 28 | void onUndoModel(); 29 | void onRedoModel(); 30 | void onReuseVF(); 31 | void onResetPoints(); 32 | 33 | void onDrawVFModeChanged(bool m); 34 | void onDrawOrigVFModeChanged(bool m); 35 | void onPinModeChanged(bool m); 36 | void onShowSelectionChanged(bool m); 37 | 38 | void onChangeAlpha(int i); 39 | void onChangeWireframe(int i); 40 | 41 | void onClearPins(); 42 | void onSaveLog(); 43 | void onRunLog(); 44 | void onResetTransform(); 45 | 46 | 47 | void onShowBdmorphEdgeClicked(bool checked); 48 | void onBdmorphOrigModel(bool checked); 49 | void onBdmorphConvertToKeyframe(); 50 | void onTargetFPSChanged(int newValue); 51 | 52 | private: 53 | ProgramState* programstate; 54 | void closeEvent (QCloseEvent *event); 55 | }; 56 | -------------------------------------------------------------------------------- /GUI/icon/i.iconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/icon/i.iconset/icon_32x32.png -------------------------------------------------------------------------------- /GUI/icon/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/icon/icon.png -------------------------------------------------------------------------------- /GUI/icon/macicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/icon/macicon.icns -------------------------------------------------------------------------------- /GUI/icon/winicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/icon/winicon.ico -------------------------------------------------------------------------------- /GUI/icon/winicon.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "winicon.ico" -------------------------------------------------------------------------------- /GUI/resources/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/resources/add.png -------------------------------------------------------------------------------- /GUI/resources/backward.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/resources/backward.png -------------------------------------------------------------------------------- /GUI/resources/pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/resources/pause.png -------------------------------------------------------------------------------- /GUI/resources/play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/resources/play.png -------------------------------------------------------------------------------- /GUI/resources/repeat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/maximlevitsky/animations-editor-bdmorph/b23885e3e5091d8ab4fa3f3f8aa24710fa26ff89/GUI/resources/repeat.png -------------------------------------------------------------------------------- /GUI/resources/resources.rc: -------------------------------------------------------------------------------- 1 | 2 | 3 | add.png 4 | 5 | 6 | backward.png 7 | repeat.png 8 | pause.png 9 | play.png 10 | 11 | 12 | ../icon/icon.png 13 | 14 | 15 | -------------------------------------------------------------------------------- /GUI/widgets/ActionButton.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "ActionButton.h" 3 | 4 | /******************************************************************************************************************************/ 5 | 6 | ActionCheckBox::ActionCheckBox(QWidget *parent) : QCheckBox(parent) 7 | { 8 | actionOwner = NULL; 9 | setCheckable(true); 10 | } 11 | /******************************************************************************************************************************/ 12 | 13 | void ActionCheckBox::setAction(QAction *action) 14 | { 15 | actionOwner = action; 16 | updateButtonStatusFromAction(); 17 | 18 | connect( action, SIGNAL(triggered()), this, SLOT(click())); 19 | connect( this, SIGNAL(clicked()), this, SLOT(updateButtonStatusFromAction())); 20 | } 21 | /******************************************************************************************************************************/ 22 | 23 | void ActionCheckBox::updateButtonStatusFromAction() 24 | { 25 | actionOwner->setChecked(this->isChecked()); 26 | } 27 | 28 | /******************************************************************************************************************************/ 29 | 30 | 31 | ActionButton::ActionButton(QWidget *parent) : QPushButton(parent) 32 | { 33 | actionOwner = NULL; 34 | setCheckable(true); 35 | } 36 | /******************************************************************************************************************************/ 37 | 38 | void ActionButton::setAction(QAction *action) 39 | { 40 | actionOwner = action; 41 | updateButtonStatusFromAction(); 42 | 43 | connect( action, SIGNAL(triggered()), this, SLOT(click())); 44 | connect( this, SIGNAL(clicked()), this, SLOT(updateButtonStatusFromAction())); 45 | } 46 | /******************************************************************************************************************************/ 47 | 48 | void ActionButton::updateButtonStatusFromAction() 49 | { 50 | actionOwner->setChecked(this->isChecked()); 51 | } 52 | -------------------------------------------------------------------------------- /GUI/widgets/ActionButton.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef ACTIONBUTTON_H 4 | #define ACTIONBUTTON_H 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | /******************************************************************************************************************************/ 12 | 13 | class ActionCheckBox : public QCheckBox 14 | { 15 | Q_OBJECT 16 | private: 17 | QAction* actionOwner; 18 | public: 19 | ActionCheckBox(QWidget *parent = 0); 20 | void setAction( QAction* action ); 21 | public slots: 22 | void updateButtonStatusFromAction(); 23 | }; 24 | 25 | /******************************************************************************************************************************/ 26 | 27 | class ActionButton : public QPushButton 28 | { 29 | Q_OBJECT 30 | private: 31 | QAction* actionOwner; 32 | public: 33 | ActionButton(QWidget *parent = 0); 34 | void setAction( QAction* action ); 35 | public slots: 36 | void updateButtonStatusFromAction(); 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | 2 | This is implementation of paper 3 | "Planar Shape Interpolation with Bounded Distortion" 4 | http://www.cs.technion.ac.il/~renjie/papers/bdmorph.pdf 5 | 6 | The code is based on earlier project, implementing the following paper: 7 | "As-Killing-As-Possible Vector Fields for Planar Deformation" 8 | http://www.stanford.edu/~justso1/assets/kvf_deformation.pdf 9 | 10 | http://www.cs.technion.ac.il/~cggc/Upload/Projects/KVFDeformation/index.html 11 | 12 | 13 | Supported platforms: Linux,Mac,Windows 14 | (+theoretically whatever CMake and Qt supports) 15 | 16 | To compile you need Qt4,Cmake, ffmpeg libaries (for video output) and 17 | suitesparse libraries (for matrix solving) 18 | 19 | On linux you rougly need these packages: 20 | 21 | cmake libqt4-dev libqt4-dev-bin 22 | libsuitesparse-metis-dev 23 | libavcodec-dev libavformat-dev libavutil-dev libswscale-dev 24 | 25 | (Exact names will vary from distribution to distribution) 26 | 27 | On windows and/or OSX you need somehow to obtain these libraries, install Qt4,Cmake, 28 | and edit the CMakefiles.txt to reflect their locations 29 | Compilation on Windows tested under Visual Studio 2008 30 | 31 | Personally I advice you that if you are using Windows, to get a real OS, like 32 | Linux or at least OSX. 33 | 34 | 35 | Project site at http://maximlevitsky.github.io/animations-editor-bdmorph/ -------------------------------------------------------------------------------- /core/BDMORPH.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef BDMORPH_H 3 | #define BDMORPH_H 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "cholmod_common.h" 10 | #include "cholmod_matrix.h" 11 | #include "cholmod_vector.h" 12 | #include "utils.h" 13 | #include "vector2d.h" 14 | #include "MeshModel.h" 15 | 16 | using std::make_pair; 17 | 18 | 19 | class TmpMemory { 20 | public: 21 | double* memory; 22 | uint16_t ptr; 23 | int maxsize; 24 | 25 | void addVar(double value) { 26 | memory[ptr++] = value; 27 | } 28 | 29 | double& operator[] (int address) { 30 | assert (address < maxsize); 31 | return memory[address]; 32 | } 33 | }; 34 | 35 | /*****************************************************************************************************/ 36 | enum command 37 | { 38 | /* compute lengths of and edge*/ 39 | COMPUTE_EDGE_LEN = 0xF0, 40 | 41 | /* compute tan(alpha)/2 for an triangle*/ 42 | COMPUTE_HALF_TAN_ANGLE, 43 | 44 | /* compute data for an vertex for next newton iteration*/ 45 | COMPUTE_VERTEX_INFO, 46 | 47 | LOAD_LENGTH_SQUARED, 48 | COMPUTE_VERTEX, 49 | }; 50 | 51 | typedef int VertexK; 52 | 53 | /*****************************************************************************************************/ 54 | class BDMORPH_BUILDER 55 | { 56 | public: 57 | BDMORPH_BUILDER(std::vector &faces, std::set& boundary_vertexes); 58 | 59 | /* Mesh helpers */ 60 | Vertex getNeighbourVertex(Vertex v1, Vertex v2) const; 61 | void getNeighbourVertices(Vertex v1, std::set& result) const; 62 | 63 | /* Main phase */ 64 | VertexK allocate_K(Vertex vertex); 65 | 66 | int compute_edge_len(Edge e); 67 | TmpMemAdddress compute_angle(Vertex p0, Vertex p1, Vertex p2); 68 | 69 | int process_vertex(Vertex v0, int neigh_count, 70 | std::vector &inner_angles, 71 | std::map > &outer_angles); 72 | 73 | /* Extraction phase */ 74 | TmpMemAdddress compute_squared_edge_len(Edge& e); 75 | void layout_vertex(Edge r0, Edge r1, Edge d, Vertex p0, Vertex p1,Vertex p2); 76 | 77 | 78 | /* output */ 79 | unsigned int getK_count() const { return external_vertex_id_to_K.size(); } 80 | unsigned int getL_count() const { return edge_L_locations.size(); } 81 | 82 | std::set& boundary_vertexes_set; 83 | 84 | /* For each edge, stores the third vertex that makes up the face, counter clockwise */ 85 | std::map edgeNeighbour; 86 | 87 | /* Stores for each vertex one of its neighbors */ 88 | std::multimap vertexNeighbours; 89 | 90 | /* information on K array - we will have here all the vertexes excluding boundary ones */ 91 | std::map external_vertex_id_to_K; 92 | 93 | /* information on L array - here we will have all the lengths, stored for final processing by extract code */ 94 | std::map edge_L_locations; 95 | 96 | /* locations of temp variables in tmpbuffer of iteration stream */ 97 | std::map angle_tmpbuf_len_variables; 98 | TmpMemAllocator mainMemoryAllocator; 99 | 100 | /* state for layout algorithm */ 101 | std::map sqr_len_tmpbuf_locations; 102 | TmpMemAllocator finalizeStepMemoryAllocator; 103 | 104 | CmdStreamBuilder iteration_stream; 105 | CmdStreamBuilder init_stream; 106 | CmdStreamBuilder extract_stream; 107 | }; 108 | 109 | /*****************************************************************************************************/ 110 | class BDMORPHModel : public MeshModel 111 | { 112 | public: 113 | BDMORPHModel(BDMORPHModel* orig); 114 | BDMORPHModel(MeshModel* orig); 115 | ~BDMORPHModel(); 116 | bool initialize(); 117 | 118 | double interpolate_frame(MeshModel *a, MeshModel* b, double t); 119 | void renderInitialEdge(double scale) const; 120 | 121 | MeshModel *modela; 122 | MeshModel *modelb; 123 | double current_t; 124 | private: 125 | 126 | OrderedEdge e0; 127 | Vector2 e0_direction; 128 | int edge1_L_location; 129 | 130 | /* lengths */ 131 | double* L0; /* interpolated metric */ 132 | double* L; /* Intermediate/final metric */ 133 | 134 | CholmodVector K; /* array of K coefficients for each non boundary vertex */ 135 | CholmodVector EnergyGradient; /* grad(E(K)) */ 136 | CholmodVector NewtonRHS; /* right size of newton method iteration linear system*/ 137 | CholmodSparseMatrix EnergyHessian; /* hessain(E(K)) */ 138 | 139 | double minAngle; 140 | double maxAngle; 141 | double grad_norm; 142 | 143 | int kCount; 144 | int edgeCount; 145 | 146 | private: 147 | /* pre-computed command steams that will guide the steps of the algorithm*/ 148 | CmdStream *init_cmd_stream; 149 | CmdStream *iteration_cmd_stream; 150 | CmdStream *extract_solution_cmd_stream; 151 | TmpMemory mem; 152 | cholmod_factor *LL; 153 | private: 154 | void metric_create_interpolated(); 155 | void calculate_grad_and_hessian(); 156 | void mertic_embed(); 157 | double getK(Vertex index) const { return index == -1 ? 0 : K[index]; } 158 | 159 | bool metric_flatten(); 160 | }; 161 | 162 | 163 | #endif 164 | -------------------------------------------------------------------------------- /core/KVFModel.h: -------------------------------------------------------------------------------- 1 | #ifndef KVF_H 2 | #define KVF_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "vector2d.h" 12 | #include "cholmod_matrix.h" 13 | #include "utils.h" 14 | #include "MeshModel.h" 15 | 16 | #define UNDOSIZE 20 17 | 18 | struct DisplacedVertex 19 | { 20 | DisplacedVertex() {} 21 | DisplacedVertex(Vertex v, Vector2 displacement) : v(v), displacement(displacement) {} 22 | Vertex v; 23 | Vector2 displacement; 24 | 25 | bool operator<(const DisplacedVertex& other) const { 26 | return this->v < other.v; 27 | } 28 | }; 29 | 30 | class KVFModel : public MeshModel 31 | { 32 | public: 33 | KVFModel(MeshModel* model); 34 | virtual ~KVFModel(); 35 | 36 | /* deformation entry points*/ 37 | void clearPins(); 38 | void setPinnedVertices(const std::set& newPins); 39 | const std::set& getPinnedVertexes() const { return pinnedVertexes; } 40 | 41 | void displaceMesh(const std::set &displacements, double alpha1); 42 | void calculateVF(const std::set &displacements, double alpha1); 43 | void applyVFLogSpiral(); 44 | void applyVF(); 45 | 46 | /* rendering */ 47 | void renderVFOrig() const; 48 | void renderVF() const; 49 | void renderOverlay(double scale) const; 50 | 51 | void historySaveToFile(std::ofstream& outfile) const; 52 | void historyLoadFromFile(std::ifstream& infile); 53 | 54 | /* undo and redo code*/ 55 | void historySnapshot(); 56 | void historyReset(); 57 | bool historyRedo(); 58 | bool historyUndo(); 59 | 60 | bool mousePressAction(Point2 pos, double radius); 61 | 62 | bool saveVOBJ(std::ofstream& ofile); 63 | bool loadVOBJ(std::ifstream& ifile); 64 | 65 | double lastVFCalcTime; 66 | double lastVFApplyTime; 67 | private: 68 | /* model information */ 69 | std::set pinnedVertexes; 70 | unsigned int lastDispsSize; 71 | 72 | /* vector field of last transformation */ 73 | Vector2 *vf; 74 | Vector2 *vfOrig; 75 | std::set disps; 76 | 77 | /* P matrix */ 78 | CholmodSparseMatrix P, Pcopy; 79 | 80 | /* pre-factor*/ 81 | cholmod_factor *L1, *L2; 82 | 83 | std::vector newPoints; 84 | std::vector counts; 85 | 86 | void renderVF_common(Vector2* VF) const; 87 | 88 | void historyAdd(const std::set &disps, double alpha); 89 | Vertex getClosestPin(Point2 point, double radius) const; 90 | void togglePinVertex(Vertex v); 91 | 92 | 93 | struct LogItem 94 | { 95 | double alpha; 96 | std::set pinnedVertexes; 97 | std::set displacedVertexes; 98 | }; 99 | 100 | struct UndoItem 101 | { 102 | /* Vertices snapshot*/ 103 | std::vector vertices; 104 | 105 | /* AKVF deformations that are needed to apply to get to this state from previous state*/ 106 | std::vector actions; 107 | }; 108 | 109 | std::vector initialVertexes; 110 | std::deque undo; 111 | std::deque redo; 112 | std::vector currentDeformLog; 113 | }; 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /core/MeshModel.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "MeshModel.h" 11 | #include "OutlineModel.h" 12 | #include "utils.h" 13 | 14 | /******************************************************************************************************************************/ 15 | 16 | MeshModel::MeshModel() : 17 | faces(new std::vector), 18 | boundaryVertices(new std::set), 19 | texCoords(new std::vector), 20 | created(true), 21 | width(0),height(0), 22 | center(0,0) 23 | { 24 | } 25 | 26 | /******************************************************************************************************************************/ 27 | 28 | MeshModel::MeshModel(const MeshModel& other): 29 | faces(other.faces), 30 | boundaryVertices(other.boundaryVertices), 31 | texCoords(other.texCoords), 32 | width(other.width),height(other.height), 33 | vertices(other.vertices), 34 | created(false), 35 | center(other.center) 36 | { 37 | /* Create a mesh model from a copy 38 | * Here we assume that we are shallow copy 39 | */ 40 | } 41 | /******************************************************************************************************************************/ 42 | 43 | bool MeshModel::loadFromFile(const std::string &filename) 44 | { 45 | bool result = false; 46 | 47 | /* Load a mesh from file */ 48 | 49 | std::ifstream infile(filename); 50 | if (infile.bad()) 51 | return false; 52 | 53 | if (ends_with(filename, "obj") || ends_with(filename, "OBJ")) 54 | result = loadOBJ(infile); 55 | else if (ends_with(filename, "off") || ends_with(filename, "OFF")) //handle off file 56 | result = loadOFF(infile); 57 | 58 | if (result == true) { 59 | printf("Model loaded: numVertices = %d, numFaces = %d\n", getNumVertices(), getNumFaces()); 60 | } 61 | 62 | return result; 63 | } 64 | /******************************************************************************************************************************/ 65 | 66 | bool MeshModel::saveToFile(const std::string filename) const 67 | { 68 | std::ofstream outfile(filename); 69 | 70 | if (outfile.bad()) 71 | return false; 72 | 73 | if (ends_with(filename, "off") || ends_with(filename, "OFF")) 74 | return saveOFF(outfile); 75 | else if (ends_with(filename, "obj") || ends_with(filename, "OBJ")) 76 | return saveOBJ(outfile); 77 | 78 | return false; 79 | } 80 | 81 | /******************************************************************************************************************************/ 82 | 83 | MeshModel::~MeshModel() 84 | { 85 | if (created) 86 | { 87 | delete faces; 88 | delete boundaryVertices; 89 | delete texCoords; 90 | } 91 | } 92 | 93 | /******************************************************************************************************************************/ 94 | 95 | bool MeshModel::updateMeshInfo() 96 | { 97 | if (getNumVertices() == 0) { 98 | printf("Loaded mesh has no vertices!\n"); 99 | return false; 100 | } 101 | 102 | if (getNumFaces() == 0) { 103 | printf("Loaded mesh has no faces!\n"); 104 | return false; 105 | } 106 | 107 | BBOX b = getActualBBox(); 108 | 109 | width = b.width(); 110 | height = b.height(); 111 | center = b.center(); 112 | 113 | std::map< int , std::map > edgeCount; 114 | std::set normalVertices; 115 | 116 | for (auto iter = faces->begin() ; iter != faces->end() ; iter++) 117 | { 118 | int a = iter->a(); 119 | int b = iter->b(); 120 | int c = iter->c(); 121 | edgeCount[a][b]++; 122 | edgeCount[b][a]++; 123 | edgeCount[a][c]++; 124 | edgeCount[c][a]++; 125 | edgeCount[c][b]++; 126 | edgeCount[b][c]++; 127 | 128 | normalVertices.insert(a); 129 | normalVertices.insert(b); 130 | normalVertices.insert(c); 131 | } 132 | 133 | if (normalVertices.size() != getNumVertices()) { 134 | printf("Mesh has standalone vertices, aborting\n"); 135 | return false; 136 | } 137 | 138 | for (auto iter = faces->begin() ; iter != faces->end() ; iter++) 139 | { 140 | int a = iter->a(); 141 | int b = iter->b(); 142 | int c = iter->c(); 143 | 144 | if (edgeCount[a][b] == 1) { 145 | boundaryVertices->insert(a); 146 | boundaryVertices->insert(b); 147 | } 148 | if (edgeCount[b][c] == 1) { 149 | boundaryVertices->insert(b); 150 | boundaryVertices->insert(c); 151 | } 152 | if (edgeCount[a][c] == 1) { 153 | boundaryVertices->insert(a); 154 | boundaryVertices->insert(c); 155 | } 156 | } 157 | 158 | return true; 159 | } 160 | /******************************************************************************************************************************/ 161 | 162 | void MeshModel::moveMesh(Vector2 newCenter) 163 | { 164 | Vector2 move = newCenter - center; 165 | for (unsigned int i = 0; i < getNumVertices(); i++) 166 | vertices[i] += move; 167 | center += move; 168 | } 169 | 170 | 171 | /******************************************************************************************************************************/ 172 | void MeshModel::renderFaces() const 173 | { 174 | glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT|GL_LINE_BIT); 175 | glEnable(GL_TEXTURE_2D); 176 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 177 | 178 | glBegin(GL_TRIANGLES); 179 | for (unsigned int i = 0; i < getNumFaces(); i++) 180 | renderFaceInternal(i); 181 | glEnd(); 182 | glPopAttrib(); 183 | } 184 | 185 | /******************************************************************************************************************************/ 186 | 187 | void MeshModel::renderWireframe() const 188 | { 189 | glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT|GL_LINE_BIT); 190 | glDisable(GL_TEXTURE_2D); 191 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 192 | glLineWidth(1.5); 193 | 194 | glBegin(GL_TRIANGLES); 195 | for (unsigned int i = 0; i < getNumFaces(); i++) 196 | renderFaceInternal(i); 197 | glEnd(); 198 | glPopAttrib(); 199 | } 200 | 201 | /******************************************************************************************************************************/ 202 | void MeshModel::renderVertex(unsigned int v, double scale) const 203 | { 204 | if (v >= getNumVertices()) 205 | return; 206 | 207 | glPushAttrib(GL_LINE_BIT); 208 | glLineWidth(1); 209 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 210 | 211 | Point2D p = vertices[v]; 212 | 213 | float s = 3 * scale; 214 | glBegin(GL_QUADS); 215 | glVertex2f(p[0]-s,p[1]-s); 216 | glVertex2f(p[0]-s,p[1]+s); 217 | glVertex2f(p[0]+s,p[1]+s); 218 | glVertex2f(p[0]+s,p[1]-s); 219 | glEnd(/*GL_QUADS*/); 220 | 221 | glPopAttrib(); 222 | } 223 | 224 | /******************************************************************************************************************************/ 225 | void MeshModel::renderFace(unsigned int fnum) const 226 | { 227 | glBegin(GL_TRIANGLES); 228 | renderFaceInternal(fnum); 229 | glEnd(); 230 | 231 | } 232 | 233 | /******************************************************************************************************************************/ 234 | 235 | void MeshModel::renderFaceInternal(unsigned int fnum) const 236 | { 237 | if (fnum >= getNumFaces()) 238 | return; 239 | 240 | std::vector &coords = *texCoords; 241 | 242 | Face &f = (*faces)[fnum]; 243 | for (unsigned int j = 0; j < 3; j++) { 244 | glTexCoord2f(coords[f[j]].x, coords[f[j]].y); 245 | glVertex2f(vertices[f[j]].x, vertices[f[j]].y); 246 | } 247 | } 248 | 249 | /******************************************************************************************************************************/ 250 | 251 | int MeshModel::getClosestVertex(Point2 point, bool onlyInnerVertex, double radius) const 252 | { 253 | int closest = -1; 254 | double closestDistance = radius; 255 | 256 | for (unsigned int i = 0; i < getNumVertices(); i++) 257 | { 258 | double distance = vertices[i].distance(point); 259 | if (distance < closestDistance) 260 | { 261 | if (onlyInnerVertex && boundaryVertices->count(i)) 262 | continue; 263 | 264 | closestDistance = distance; 265 | closest = i; 266 | } 267 | } 268 | return closest; 269 | } 270 | 271 | /******************************************************************************************************************************/ 272 | 273 | int MeshModel::getFaceUnderPoint(Point2 point) const 274 | { 275 | for (unsigned int i=0; i < getNumFaces() ; i++) { 276 | Face& face = (*faces)[i]; 277 | if (PointInTriangle(point, vertices[face.a()],vertices[face.b()],vertices[face.c()])) 278 | return i; 279 | } 280 | 281 | return -1; 282 | } 283 | 284 | /******************************************************************************************************************************/ 285 | BBOX MeshModel::getActualBBox() const 286 | { 287 | return BBOX(vertices); 288 | } 289 | 290 | /******************************************************************************************************************************/ 291 | 292 | bool MeshModel::loadOFF(std::ifstream& infile) 293 | { 294 | std::string temp; 295 | infile >> temp; 296 | unsigned int numVertices,numFaces; 297 | infile >> numVertices >> numFaces >> temp; 298 | 299 | if (infile.eof()) 300 | return false; 301 | 302 | vertices.resize(numVertices); 303 | double z; 304 | 305 | for (unsigned int i = 0; i < numVertices; i++) { 306 | if (infile.eof()) return false; 307 | infile >> vertices[i].x >> vertices[i].y >> z; 308 | } 309 | 310 | 311 | int three; 312 | faces->resize(numFaces); 313 | 314 | for (unsigned int i = 0; i < numFaces; i++) { 315 | if (infile.eof()) return false; 316 | infile >> three >> (*faces)[i][0] >> (*faces)[i][1] >> (*faces)[i][2]; 317 | } 318 | 319 | identityTexCoords(); 320 | return updateMeshInfo(); 321 | } 322 | 323 | /******************************************************************************************************************************/ 324 | 325 | bool MeshModel::saveOFF(std::ofstream& ofile) const 326 | { 327 | ofile << "OFF\n"; 328 | ofile << getNumVertices() << ' ' << getNumFaces() << " 0\n"; // don't bother counting edges 329 | 330 | for (unsigned int i = 0; i < getNumVertices(); i++) 331 | ofile << vertices[i][0] << ' ' << vertices[i][1] << " 0\n"; 332 | 333 | for (unsigned int i = 0; i < getNumFaces(); i++) 334 | ofile << "3 " << (*faces)[i][0] << ' ' << (*faces)[i][1] << ' ' << (*faces)[i][2] << std::endl; 335 | 336 | return true; 337 | } 338 | 339 | /******************************************************************************************************************************/ 340 | 341 | bool MeshModel::loadOBJ(std::ifstream& infile) 342 | { 343 | double x,y,z; 344 | bool hasUV = false; 345 | std::string a,b,c; 346 | 347 | while (!infile.eof()) 348 | { 349 | // get line 350 | std::string curLine; 351 | std::getline(infile, curLine); 352 | 353 | // read type of the line 354 | std::istringstream issLine(curLine); 355 | std::string linetype; 356 | issLine >> linetype; 357 | 358 | if (linetype == "v") 359 | { 360 | issLine >> x >> y >> z; 361 | Point2 p(x,y); 362 | vertices.push_back(p); 363 | continue; 364 | } 365 | if (linetype == "vt") 366 | { 367 | hasUV = true; 368 | issLine >> x >> y; 369 | Point2 p(x,y); 370 | texCoords->push_back(p); 371 | continue; 372 | } 373 | if (linetype == "f") 374 | { 375 | issLine >> a >> b >> c; 376 | char* a_dup = strdup(a.c_str()); 377 | char* b_dup = strdup(b.c_str()); 378 | char* c_dup = strdup(c.c_str()); 379 | 380 | char* aa = strtok(a_dup,"/"); 381 | char* bb = strtok(b_dup,"/"); 382 | char* cc = strtok(c_dup,"/"); 383 | Face fa; 384 | fa.f[0] = atoi(aa)-1; 385 | fa.f[1] = atoi(bb)-1; 386 | fa.f[2] = atoi(cc)-1; 387 | 388 | faces->push_back(fa); 389 | 390 | free(a_dup); 391 | free(b_dup); 392 | free(c_dup); 393 | 394 | continue; 395 | } 396 | if (linetype == "#") continue; 397 | if (linetype == "mtllib") continue; 398 | } 399 | 400 | if (hasUV == false) 401 | identityTexCoords(); 402 | 403 | return updateMeshInfo(); 404 | 405 | } 406 | /******************************************************************************************************************************/ 407 | 408 | bool MeshModel::saveOBJ(std::ofstream& ofile) const 409 | { 410 | for (unsigned int i = 0; i < getNumVertices(); i++) 411 | ofile << "v " << vertices[i][0] << ' ' << vertices[i][1] << " 0\n"; 412 | 413 | for (unsigned int i = 0; i < getNumVertices(); i++) 414 | ofile << "vt " << (*texCoords)[i][0] << ' ' << (*texCoords)[i][1] << std::endl; 415 | 416 | for (unsigned int i = 0; i < getNumFaces(); i++) 417 | ofile << "f " << 418 | (*faces)[i][0]+1 << '/' << (*faces)[i][0]+1 << ' ' << 419 | (*faces)[i][1]+1 << '/' << (*faces)[i][1]+1 << ' ' << 420 | (*faces)[i][2]+1 << '/' << (*faces)[i][2]+1 << std::endl; 421 | 422 | return true; 423 | } 424 | 425 | /******************************************************************************************************************************/ 426 | 427 | void MeshModel::identityTexCoords() 428 | { 429 | texCoords->resize(getNumVertices()); 430 | for (unsigned int i = 0; i < getNumVertices(); i++) 431 | (*texCoords)[i] = vertices[i]; 432 | 433 | } 434 | 435 | /******************************************************************************************************************************/ 436 | 437 | bool MeshModel::saveVOBJFaces(std::ofstream& ofile) const 438 | { 439 | for (unsigned int i = 0; i < getNumFaces(); i++) 440 | ofile << (*faces)[i][0] << ' ' << (*faces)[i][1] << ' ' << (*faces)[i][2] << std::endl; 441 | return true; 442 | } 443 | /******************************************************************************************************************************/ 444 | 445 | bool MeshModel::saveVOBJTexCoords(std::ofstream& ofile) const 446 | { 447 | for (unsigned int i = 0; i < getNumVertices(); i++) 448 | ofile << (*texCoords)[i][0] << ' ' << (*texCoords)[i][1] << std::endl; 449 | return true; 450 | } 451 | 452 | /******************************************************************************************************************************/ 453 | 454 | bool MeshModel::saveVOBJVertices(std::ofstream& ofile) const 455 | { 456 | for (unsigned int i = 0; i < getNumVertices(); i++) 457 | ofile << vertices[i][0] << ' ' << vertices[i][1] << std::endl; 458 | return true; 459 | } 460 | 461 | /******************************************************************************************************************************/ 462 | 463 | bool MeshModel::loadVOBJFaces(std::ifstream& infile) 464 | { 465 | for (unsigned int i = 0; i < getNumFaces(); i++) 466 | { 467 | if (infile.eof()) return false; 468 | infile >> (*faces)[i][0] >> (*faces)[i][1] >> (*faces)[i][2]; 469 | } 470 | return true; 471 | } 472 | 473 | /******************************************************************************************************************************/ 474 | 475 | bool MeshModel::loadVOBJVertices(std::ifstream& infile) 476 | { 477 | for (unsigned int i = 0; i < getNumVertices(); i++) { 478 | if (infile.eof()) return false; 479 | infile >> vertices[i].x >> vertices[i].y; 480 | } 481 | 482 | return true; 483 | } 484 | /******************************************************************************************************************************/ 485 | 486 | bool MeshModel::loadVOBJTexCoords(std::ifstream& infile) 487 | { 488 | texCoords->resize(getNumVertices()); 489 | for (unsigned int i = 0; i < getNumVertices(); i++) { 490 | if (infile.eof()) return false; 491 | infile >> (*texCoords)[i][0] >> (*texCoords)[i][1]; 492 | } 493 | return true; 494 | } 495 | /******************************************************************************************************************************/ 496 | 497 | 498 | 499 | -------------------------------------------------------------------------------- /core/MeshModel.h: -------------------------------------------------------------------------------- 1 | #ifndef MODEL2D_H 2 | #define MODEL2D_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "vector2d.h" 9 | #include "utils.h" 10 | 11 | class OutlineModel; 12 | 13 | /******************************************************************************************************************************/ 14 | class MeshModel 15 | { 16 | public: 17 | MeshModel(); 18 | MeshModel(const MeshModel& other); 19 | virtual ~MeshModel(); 20 | 21 | double getWidth() const { return width; } 22 | double getHeight() const { return height; } 23 | virtual BBOX getActualBBox() const; 24 | 25 | unsigned int getNumVertices() const { return vertices.size(); } 26 | unsigned int getNumFaces() const { return faces->size(); } 27 | 28 | int getClosestVertex(Point2 point, bool onlyInnerVertex = false, double radius = std::numeric_limits::max()) const; 29 | int getFaceUnderPoint(Point2 point) const; 30 | 31 | /* rendering */ 32 | virtual void renderFaces() const; 33 | virtual void renderWireframe() const; 34 | virtual void renderOverlay(double scale) const {} 35 | 36 | /* undo/redo */ 37 | 38 | virtual void historySnapshot() {} 39 | 40 | virtual void historyReset() {} 41 | virtual bool historyRedo() { return false;} 42 | virtual bool historyUndo() { return false;} 43 | 44 | void renderVertex(unsigned int v, double scale) const; 45 | void renderFace(unsigned int f) const; 46 | 47 | /* common shared model information */ 48 | std::vector *faces; 49 | std::set *boundaryVertices; 50 | std::vector *texCoords; 51 | 52 | double width; 53 | double height; 54 | Point2 center; 55 | 56 | /* vertices - one per each model */ 57 | std::vector vertices; 58 | 59 | bool loadOBJ(std::ifstream& infile); 60 | bool loadOFF(std::ifstream& infile); 61 | bool saveOFF(std::ofstream& ofile) const; 62 | bool saveOBJ(std::ofstream& ofile) const; 63 | 64 | virtual bool mousePressAction(Point2 pos, double radius) { return false;} 65 | virtual bool mouseReleaseAction(Point2 pos, bool moved, double radius, bool rightButton) { return false;} 66 | virtual bool moveAction(Point2 pos1, Point2 pos2, double radius) { return false;} 67 | 68 | virtual bool saveToFile(const std::string filename) const; 69 | virtual bool loadFromFile(const std::string &filename); 70 | 71 | bool loadVOBJFaces(std::ifstream& infile); 72 | bool loadVOBJTexCoords(std::ifstream& ofile); 73 | bool loadVOBJVertices(std::ifstream& infile); 74 | 75 | bool saveVOBJFaces(std::ofstream& ofile) const; 76 | bool saveVOBJTexCoords(std::ofstream& ofile) const; 77 | bool saveVOBJVertices(std::ofstream& ofile) const; 78 | 79 | void identityTexCoords(); 80 | bool updateMeshInfo(); 81 | void moveMesh(Vector2 newCenter); 82 | 83 | private: 84 | bool created; 85 | void renderFaceInternal(unsigned int fnum) const; 86 | 87 | }; 88 | 89 | /******************************************************************************************************************************/ 90 | 91 | #endif // MODEL2D_H 92 | -------------------------------------------------------------------------------- /core/OutlineModel.h: -------------------------------------------------------------------------------- 1 | #ifndef OUTLINEMODEL_H_ 2 | #define OUTLINEMODEL_H_ 3 | 4 | #include "MeshModel.h" 5 | #include "utils.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | class OutlineModel: public MeshModel 13 | { 14 | public: 15 | OutlineModel(); 16 | OutlineModel(MeshModel *from); 17 | OutlineModel(const QImage &from); 18 | virtual ~OutlineModel(); 19 | 20 | virtual void renderFaces() const; 21 | virtual void renderWireframe() const; 22 | virtual void renderOverlay(double scale) const; 23 | 24 | virtual bool mouseReleaseAction(Point2 pos, bool moved, double radius, bool rightButton); 25 | virtual bool moveAction(Point2 pos1, Point2 pos2, double radius); 26 | 27 | virtual bool saveToFile(const std::string filename) const; 28 | virtual bool loadFromFile(const std::string &filename); 29 | bool createMesh(MeshModel *out, int triCount) const; 30 | 31 | void setScale(double sX, double sY); 32 | 33 | std::set edges; 34 | 35 | private: 36 | Vertex selectedVertex; 37 | double scaleX; 38 | double scaleY; 39 | 40 | Vertex addVertex(Point2 p); 41 | void deleteVertex(Vertex v); 42 | 43 | virtual void historySnapshot(); 44 | virtual void historyReset(); 45 | virtual bool historyRedo(); 46 | virtual bool historyUndo(); 47 | 48 | void getVertices(std::set &standaloneVertices, std::set &normalVertices) const; 49 | void renderInternal() const; 50 | 51 | BBOX getActualBBox() const; 52 | 53 | struct UndoItem 54 | { 55 | std::vector vertices; 56 | std::set edges; 57 | Vertex selectedVertex; 58 | }; 59 | 60 | std::deque undo; 61 | std::deque redo; 62 | 63 | }; 64 | #endif /* OUTLINEMODEL_H_ */ 65 | -------------------------------------------------------------------------------- /core/VideoModel.cpp: -------------------------------------------------------------------------------- 1 | #include "VideoModel.h" 2 | #include "BDMORPH.h" 3 | #include 4 | #include 5 | 6 | /******************************************************************************************************************************/ 7 | VideoModel::VideoModel() : pFrame(NULL) 8 | {} 9 | 10 | 11 | /******************************************************************************************************************************/ 12 | VideoModel::VideoModel(OutlineModel* outlineModel, int trianglecount) : pFrame(NULL) 13 | { 14 | if (!outlineModel->createMesh(this, trianglecount)) 15 | return; 16 | if (!initialize_animations()) 17 | return; 18 | initialize_keyframes(); 19 | } 20 | 21 | /******************************************************************************************************************************/ 22 | VideoModel::~VideoModel() 23 | { 24 | for (auto iter = keyframes.begin(); iter != keyframes.end() ;) { 25 | delete *iter; 26 | iter = keyframes.erase(iter); 27 | } 28 | 29 | delete pFrame; 30 | } 31 | /******************************************************************************************************************************/ 32 | 33 | bool VideoModel::loadFromFile(const std::string &filename) 34 | { 35 | if (!ends_with(filename, ".vproject")) 36 | return false; 37 | 38 | std::ifstream infile(filename); 39 | if (infile.bad()) 40 | return false; 41 | 42 | std::string magic; 43 | infile >> magic; 44 | if (magic != "VOBJ") 45 | return false; 46 | 47 | int keyFrameCount,numFaces,numVertices; 48 | infile >> numFaces >> numVertices >> keyFrameCount; 49 | 50 | faces->resize(numFaces); 51 | vertices.resize(numVertices); 52 | 53 | if (keyFrameCount == 0 || numFaces == 0 || numVertices == 0) 54 | return false; 55 | 56 | loadVOBJFaces(infile); 57 | loadVOBJTexCoords(infile); 58 | loadVOBJVertices(infile); 59 | 60 | updateMeshInfo(); 61 | 62 | for (int i = 0 ; i < keyFrameCount ; i++) 63 | { 64 | int duration; 65 | infile >> magic >> duration; 66 | VideoKeyFrame* frame = new VideoKeyFrame(this); 67 | frame->loadVOBJ(infile); 68 | frame->duration = duration; 69 | keyframes.push_back(frame); 70 | } 71 | 72 | return initialize_animations(); 73 | } 74 | /******************************************************************************************************************************/ 75 | 76 | bool VideoModel::createFromFile(const std::string &filename) 77 | { 78 | bool retval = MeshModel::loadFromFile(filename); 79 | if (!retval) return false; 80 | retval = initialize_animations(); 81 | if (!retval) return false; 82 | initialize_keyframes(); 83 | return true; 84 | } 85 | 86 | /******************************************************************************************************************************/ 87 | 88 | bool VideoModel::saveToFile(const std::string filename) const 89 | { 90 | std::ofstream outfile(filename); 91 | if (outfile.bad()) 92 | return false; 93 | if (!ends_with(filename, ".vproject")) 94 | return false; 95 | 96 | outfile << "VOBJ" << std::endl; 97 | outfile << getNumFaces() << " " << getNumVertices() << " " << keyframes.size() << std::endl; 98 | 99 | saveVOBJFaces(outfile); 100 | saveVOBJTexCoords(outfile); 101 | saveVOBJVertices(outfile); 102 | 103 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) 104 | { 105 | VideoKeyFrame *keyframe = *iter; 106 | outfile << "keyframe" << " " << keyframe->duration << std::endl; 107 | keyframe->saveVOBJ(outfile); 108 | } 109 | 110 | return true; 111 | } 112 | /******************************************************************************************************************************/ 113 | 114 | bool VideoModel::initialize_animations() 115 | { 116 | pFrame = new BDMORPHModel(this); 117 | bool result = pFrame->initialize(); 118 | if (!result) return false; 119 | return true; 120 | } 121 | /******************************************************************************************************************************/ 122 | 123 | void VideoModel::initialize_keyframes() 124 | { 125 | keyframes.push_back(new VideoKeyFrame(this)); 126 | keyframes.push_back(new VideoKeyFrame(this)); 127 | } 128 | 129 | /******************************************************************************************************************************/ 130 | 131 | int VideoModel::keyframesCount() const 132 | { 133 | return keyframes.size(); 134 | } 135 | 136 | /******************************************************************************************************************************/ 137 | int VideoModel::getTotalTime() const 138 | { 139 | int retval = 0; 140 | int last_time = 0; 141 | 142 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) { 143 | retval += (*iter)->duration; 144 | last_time = (*iter)->duration; 145 | } 146 | retval -= last_time; 147 | return retval; 148 | } 149 | 150 | /******************************************************************************************************************************/ 151 | VideoKeyFrame* VideoModel::getKeyframeByIndex(int index) const 152 | { 153 | if (index >= 0 && index < (int)keyframes.size()) 154 | return keyframes[index]; 155 | return NULL; 156 | } 157 | /******************************************************************************************************************************/ 158 | VideoKeyFrame* VideoModel::getLastKeyframeBeforeTime(int msecs) const 159 | { 160 | int time = 0; 161 | 162 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) 163 | { 164 | time += (*iter)->duration; 165 | 166 | if (time > msecs) 167 | return *iter; 168 | } 169 | 170 | return keyframes.back(); 171 | } 172 | /******************************************************************************************************************************/ 173 | int VideoModel::getKeyFrameIndex(VideoKeyFrame* frame) const 174 | { 175 | int i = 0; 176 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++, i++) 177 | { 178 | if (*iter == frame) 179 | return i; 180 | } 181 | 182 | return -1; 183 | } 184 | /******************************************************************************************************************************/ 185 | int VideoModel::getKeyFrameTimeMsec(VideoKeyFrame* frame) const 186 | { 187 | int time = 0; 188 | 189 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) { 190 | if (*iter == frame) 191 | break; 192 | time += (*iter)->duration; 193 | } 194 | 195 | return time; 196 | } 197 | /******************************************************************************************************************************/ 198 | VideoKeyFrame* VideoModel::forkFrame(VideoKeyFrame* reference) 199 | { 200 | /* inserts new keyframe after this one */ 201 | auto iter = std::find(keyframes.begin(), keyframes.end(),reference); 202 | assert (iter != keyframes.end()); 203 | 204 | VideoKeyFrame *frame; 205 | frame = new VideoKeyFrame(reference); 206 | 207 | keyframes.insert(iter + 1, frame); 208 | return frame; 209 | } 210 | 211 | 212 | /******************************************************************************************************************************/ 213 | VideoKeyFrame* VideoModel::insertFrame(int time, BDMORPHModel* points) 214 | { 215 | VideoKeyFrame* FrameA = getLastKeyframeBeforeTime(time); 216 | VideoKeyFrame* FrameB = new VideoKeyFrame(points); 217 | 218 | KVFModel* kvfModelA = dynamic_cast(FrameA); 219 | FrameB->setPinnedVertices(kvfModelA->getPinnedVertexes()); 220 | 221 | int newFrameADuration = time - getKeyFrameTimeMsec(FrameA); 222 | if (newFrameADuration <= 1) 223 | newFrameADuration = 1; 224 | 225 | int newFrameBDuration = FrameA->duration - newFrameADuration; 226 | if (newFrameBDuration <= 1) 227 | newFrameBDuration = 1; 228 | 229 | FrameA->duration = newFrameADuration; 230 | FrameB->duration = newFrameBDuration; 231 | 232 | /* inserts new keyframe after this one */ 233 | auto iter = std::find(keyframes.begin(), keyframes.end(),FrameA); 234 | assert (iter != keyframes.end()); 235 | keyframes.insert(iter + 1, FrameB); 236 | return FrameB; 237 | } 238 | 239 | /******************************************************************************************************************************/ 240 | VideoKeyFrame* VideoModel::deleteFrame(VideoKeyFrame* frame) 241 | { 242 | assert (keyframes.size() > 1); 243 | int id = getKeyFrameIndex(frame); 244 | 245 | auto iter = std::find(keyframes.begin(), keyframes.end(),frame); 246 | assert (iter != keyframes.end()); 247 | delete *iter; 248 | keyframes.erase(iter); 249 | 250 | if (id > 0) id--; 251 | return getKeyframeByIndex(id); 252 | } 253 | 254 | /******************************************************************************************************************************/ 255 | 256 | MeshModel* VideoModel::interpolateFrame(double msec, double* timeduration) 257 | { 258 | int prevTime = 0,duration = 0; 259 | VideoKeyFrame *prevFrame = NULL, *nextFrame = NULL; 260 | 261 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) 262 | { 263 | duration = (*iter)->duration; 264 | 265 | if (prevTime + duration > msec) 266 | { 267 | prevFrame = *iter; 268 | iter++; 269 | nextFrame = iter == keyframes.end() ? prevFrame : *iter; 270 | break; 271 | } 272 | 273 | prevTime += duration; 274 | } 275 | 276 | if (!prevFrame || duration == 0) 277 | return NULL; 278 | 279 | double t = (double)(msec - prevTime) / duration; 280 | *timeduration =pFrame->interpolate_frame(prevFrame,nextFrame,t); 281 | 282 | if (*timeduration != -1) 283 | return pFrame; 284 | else 285 | return NULL; 286 | } 287 | 288 | /******************************************************************************************************************************/ 289 | 290 | BBOX VideoModel::getActualBBox() const 291 | { 292 | BBOX b(vertices); 293 | 294 | for (auto iter = keyframes.begin() ; iter != keyframes.end() ; iter++) 295 | { 296 | b += (*iter)->getActualBBox(); 297 | } 298 | return b; 299 | } 300 | -------------------------------------------------------------------------------- /core/VideoModel.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef VIDEOMODEL_H_ 3 | #define VIDEOMODEL_H_ 4 | 5 | #include 6 | #include 7 | #include "KVFModel.h" 8 | #include "BDMORPH.h" 9 | #include "OutlineModel.h" 10 | 11 | /****************************************************************************/ 12 | class VideoKeyFrame : public KVFModel 13 | { 14 | public: 15 | VideoKeyFrame(MeshModel* m) : KVFModel(m), duration(200) {} 16 | int duration; 17 | }; 18 | 19 | /****************************************************************************/ 20 | class VideoModel : public MeshModel 21 | { 22 | public: 23 | VideoModel(); 24 | VideoModel(OutlineModel* outlineModel, int trianglecount); 25 | 26 | bool createFromFile(const std::string &filename); 27 | virtual ~VideoModel(); 28 | 29 | MeshModel* interpolateFrame(double msec, double *timeduration_out); 30 | 31 | /* creates a new frame as a clone of existing frame*/ 32 | VideoKeyFrame* forkFrame(VideoKeyFrame* reference); 33 | 34 | /* creates new keyframe at specified time using a model */ 35 | VideoKeyFrame* insertFrame(int time, BDMORPHModel* points); 36 | 37 | 38 | /* deletes an key frame, will ignore case where frame exists and will return prevous frame */ 39 | VideoKeyFrame* deleteFrame(VideoKeyFrame* frame); 40 | 41 | /* gets an frame at specified index. Index may change over time */ 42 | VideoKeyFrame* getKeyframeByIndex(int index) const; 43 | 44 | VideoKeyFrame* getLastKeyframeBeforeTime(int msecs) const; 45 | 46 | int keyframesCount() const; 47 | int getKeyFrameIndex(VideoKeyFrame* frame) const; 48 | int getKeyFrameTimeMsec(VideoKeyFrame* frame) const; 49 | int getTotalTime() const; 50 | 51 | /* interpolated frame */ 52 | BDMORPHModel *pFrame; 53 | 54 | virtual bool saveToFile(const std::string filename) const; 55 | virtual bool loadFromFile(const std::string &filename); 56 | virtual BBOX getActualBBox() const; 57 | 58 | private: 59 | std::vector keyframes; 60 | bool initialize_animations(); 61 | void initialize_keyframes(); 62 | }; 63 | 64 | #endif /* VIDEOMODEL_H_ */ 65 | -------------------------------------------------------------------------------- /utils/cholmod_common.cpp: -------------------------------------------------------------------------------- 1 | #include "cholmod_common.h" 2 | #include 3 | 4 | /******************************************************************************************************************************/ 5 | static cholmod_common common; 6 | static bool cholmod_common_initilaized = false; 7 | 8 | 9 | /******************************************************************************************************************************/ 10 | /*static void cholmod_error_handler(int status, char *file, int line, char *message) 11 | { 12 | printf("CHOLMOD error status %d\n", status); 13 | printf("File: %s\n", file); 14 | printf("Line: %d\n", line); 15 | printf("Message: %s\n", message); 16 | }*/ 17 | 18 | /******************************************************************************************************************************/ 19 | cholmod_common* cholmod_get_common() 20 | { 21 | assert(cholmod_common_initilaized); 22 | return &common; 23 | } 24 | 25 | /******************************************************************************************************************************/ 26 | void cholmod_initialize() 27 | { 28 | if (!cholmod_common_initilaized) { 29 | cholmod_common_initilaized = true; 30 | cholmod_start(&common); 31 | //common.error_handler = cholmod_error_handler; 32 | common.final_asis = 1; 33 | common.supernodal = CHOLMOD_SIMPLICIAL; 34 | } 35 | } 36 | 37 | /******************************************************************************************************************************/ 38 | void cholmod_finalize() { 39 | if (cholmod_common_initilaized) 40 | cholmod_finish(&common); 41 | } 42 | -------------------------------------------------------------------------------- /utils/cholmod_common.h: -------------------------------------------------------------------------------- 1 | #ifndef CHOLMOD_COMMON_H 2 | #define CHOLMOD_COMMON_H 3 | 4 | #include 5 | 6 | cholmod_common* cholmod_get_common(); 7 | void cholmod_finalize(); 8 | void cholmod_initialize(); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /utils/cholmod_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "cholmod_matrix.h" 2 | #include "cholmod_vector.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define ABS(x) (((x)<0)?-(x):(x)) 11 | 12 | /******************************************************************************************************************************/ 13 | CholmodSparseMatrix::CholmodSparseMatrix(CholmodSparseMatrix::Type type) 14 | : nr(0), nc(0), numNonzero(0), values(NULL), rowStart(NULL), column(NULL), type(type), capacity(0),rowCapacity(0) 15 | {} 16 | 17 | /******************************************************************************************************************************/ 18 | 19 | CholmodSparseMatrix::CholmodSparseMatrix(CholmodSparseMatrix::Type type, int r, int c, int nz) 20 | : nr(r), nc(c), numNonzero(0), capacity(nz), type(type), values(NULL), rowStart(NULL), column(NULL) 21 | { 22 | reshape(r,c,nz); 23 | } 24 | 25 | /******************************************************************************************************************************/ 26 | 27 | CholmodSparseMatrix::~CholmodSparseMatrix() 28 | { 29 | free(values); 30 | free(rowStart); 31 | free(column); 32 | } 33 | 34 | /******************************************************************************************************************************/ 35 | void CholmodSparseMatrix::reshape(unsigned int r, unsigned int c, unsigned int cap) 36 | { 37 | if (r != nr || c != nc) 38 | { 39 | if (type != ASSYMETRIC) 40 | assert(r == c); 41 | 42 | if (r > rowCapacity) { 43 | rowStart = (unsigned int*) (realloc(rowStart, (r+1) * sizeof(unsigned int))); 44 | rowCapacity = r; 45 | } 46 | 47 | nr = r; 48 | nc = c; 49 | } 50 | setCapacity(cap); 51 | } 52 | 53 | /******************************************************************************************************************************/ 54 | void CholmodSparseMatrix::setCapacity(unsigned int c) 55 | { 56 | if (capacity >= c) 57 | return; 58 | 59 | capacity = c; 60 | values = (double*) (realloc((void*) (values), capacity * sizeof(double))); 61 | column = (unsigned int*) (realloc((void*) (column), 62 | capacity * sizeof(unsigned int))); 63 | } 64 | 65 | /******************************************************************************************************************************/ 66 | 67 | void CholmodSparseMatrix::startMatrixFill() { 68 | curLocation = 0; 69 | lastR = -1; 70 | numNonzero = 0; 71 | } 72 | /******************************************************************************************************************************/ 73 | 74 | double CholmodSparseMatrix::infinityNorm() 75 | { 76 | double max = 0; 77 | for (unsigned int i = 0; i < nr; i++) { 78 | double rowSum = 0; 79 | 80 | for (unsigned int j = rowStart[i]; j < rowEnd(i); j++) 81 | rowSum += ABS(values[j]); 82 | 83 | max = (max < rowSum)?rowSum:max; 84 | } 85 | return max; 86 | } 87 | 88 | /******************************************************************************************************************************/ 89 | void CholmodSparseMatrix::transpose(CholmodSparseMatrix &result) 90 | { 91 | result.reshape(nc,nr,numNonzero); 92 | 93 | // colSize is malloc'ed -- eventually we should allocate it elsewhere 94 | unsigned int *colSize = (unsigned int*)malloc(nc*sizeof(int)); 95 | memset(colSize, 0, nc*sizeof(int)); 96 | 97 | for (unsigned int i = 0; i < numNonzero; i++) colSize[ column[i] ]++; 98 | 99 | result.rowStart[0] = 0; 100 | for (unsigned int i = 1; i < nc; i++) 101 | result.rowStart[i] = result.rowStart[i-1] + colSize[i-1]; 102 | 103 | if (result.rowStart[nc-1] + colSize[nc-1] != numNonzero) { 104 | printf("Something wrong with transpose!\n"); 105 | exit(0); 106 | } 107 | 108 | // now, reuse colSize to tell us how many things we've written 109 | memset(colSize, 0, nc*sizeof(int)); 110 | for (unsigned int i = 0; i < nr; i++) 111 | for (unsigned int j = rowStart[i]; j < rowEnd(i); j++) { 112 | int position = colSize[ column[j] ]++; 113 | position += result.rowStart[ column[j] ]; 114 | 115 | result.values[position] = values[j]; 116 | result.column[position] = i; 117 | } 118 | free(colSize); 119 | } 120 | 121 | /******************************************************************************************************************************/ 122 | void CholmodSparseMatrix::stack(CholmodSparseMatrix **matrices, unsigned int numMatrices, unsigned int *colShifts) 123 | { 124 | CholmodSparseMatrix &result = *this; 125 | unsigned int nonzeroSum = 0, rowSum = 0, maxCol = 0; 126 | for (unsigned int i = 0; i < numMatrices; i++) { 127 | nonzeroSum += matrices[i]->numNonzero; 128 | rowSum += matrices[i]->nr; 129 | maxCol = std::max(maxCol, matrices[i]->nc + colShifts[i]); 130 | } 131 | 132 | result.reshape(rowSum,maxCol,nonzeroSum); 133 | result.startMatrixFill(); 134 | 135 | unsigned int rowShift = 0; 136 | for (unsigned int i = 0; i < numMatrices; i++) { 137 | for (unsigned int j = 0; j < matrices[i]->nr; j++) 138 | for (unsigned int k = matrices[i]->rowStart[j]; k < matrices[i]->rowEnd(j); k++) 139 | result.addElement(j+rowShift,matrices[i]->column[k]+colShifts[i],matrices[i]->values[k]); 140 | rowShift += matrices[i]->nr; 141 | } 142 | } 143 | 144 | /******************************************************************************************************************************/ 145 | void CholmodSparseMatrix::multiply(CholmodSparseMatrix &m, CholmodSparseMatrix &result) 146 | { 147 | std::map rowValues; // for a given column, holds nonzero values 148 | unsigned int curNonzero = 0; 149 | 150 | if (result.capacity == 0) 151 | result.setCapacity(200); 152 | 153 | result.reshape(nr,m.nc,result.capacity); 154 | result.startMatrixFill(); 155 | 156 | for (unsigned int i = 0; i < nr; i++) { // compute the i-th row 157 | 158 | result.rowStart[i] = curNonzero; 159 | rowValues.clear(); // start out with zeroes 160 | 161 | unsigned int end = rowEnd(i); 162 | 163 | for (unsigned int p = rowStart[i]; p < end; p++) { // for all elements in row i 164 | int k = column[p]; // this is the k-th column 165 | double value = values[p]; // value = element (i,k) 166 | 167 | int stop = m.rowEnd(k); 168 | for (int q = m.rowStart[k]; q < stop; q++) // look at row k in matrix m 169 | rowValues[ m.column[q] ] += value * m.values[q]; // add (i,k) * (k,q) 170 | } 171 | 172 | // now, copy those values into the matrix 173 | while (curNonzero + (int)rowValues.size() > result.capacity) result.setCapacity(result.capacity*2); 174 | 175 | // this better traverse in sorted order... 176 | for (auto it = rowValues.begin(); it != rowValues.end(); ++it) { 177 | //if (ABS(it->second) > numeric_limits::epsilon()) 178 | result.addElement(i,it->first,it->second); 179 | } 180 | 181 | curNonzero += rowValues.size(); 182 | } 183 | } 184 | 185 | /******************************************************************************************************************************/ 186 | CholmodSparseMatrix& CholmodSparseMatrix::operator =(const CholmodSparseMatrix& m) 187 | { 188 | reshape(m.nr, m.nc, m.capacity); 189 | numNonzero = m.numNonzero; 190 | memcpy(values, m.values, numNonzero * sizeof(double)); 191 | memcpy(rowStart, m.rowStart, nr * sizeof(int)); 192 | memcpy(column, m.column, numNonzero * sizeof(int)); 193 | return *this; 194 | } 195 | 196 | /******************************************************************************************************************************/ 197 | void CholmodSparseMatrix::addConstraint(const std::vector& rows,double alpha) 198 | { 199 | int oldRows = nr; 200 | reshape(nr + rows.size(), nc, capacity + rows.size()); 201 | for (unsigned int i = 0; i < rows.size(); i++) { 202 | values[numNonzero] = alpha; 203 | column[numNonzero] = rows[i]; 204 | rowStart[i + oldRows] = numNonzero++; 205 | } 206 | } 207 | 208 | /******************************************************************************************************************************/ 209 | double* CholmodSparseMatrix::addElement(unsigned int r, unsigned int c, double value) 210 | { 211 | if (lastR != (int)r) 212 | { 213 | /* starting new row, */ 214 | assert ((int)r > lastR); 215 | while (lastR < (int)r) 216 | rowStart[++lastR] = curLocation; 217 | } 218 | 219 | assert(r < nr); 220 | assert(c < nc); 221 | 222 | if (type == UPPER_TRANGULAR) 223 | assert(c >= r); 224 | if (type == LOWER_TRIANGULAR) 225 | assert(c <= r); 226 | 227 | if (curLocation >= capacity) { 228 | printf("Too far: %d %d", curLocation, capacity); 229 | exit(0); 230 | } 231 | 232 | values[curLocation] = value; 233 | column[curLocation] = c; 234 | numNonzero++; 235 | curLocation++; 236 | return &values[curLocation-1]; 237 | } 238 | 239 | /******************************************************************************************************************************/ 240 | void CholmodSparseMatrix::multiply(CholmodVector &x, CholmodVector &b) 241 | { 242 | for (unsigned int i = 0; i < nr; i++) 243 | b[i] = 0; 244 | 245 | switch(type) { 246 | case ASSYMETRIC: 247 | for (unsigned int i = 0; i < nr; i++) 248 | for (unsigned int j = rowStart[i]; j < rowEnd(i); j++) 249 | b[i] += values[j] * x[column[j]]; 250 | break; 251 | case LOWER_TRIANGULAR: 252 | for (unsigned int i = 0; i < nr; i++) 253 | for (unsigned int j = rowStart[i]; j < rowEnd(i) && column[j] <= i; j++) 254 | b[i] += values[j] * x[column[j]]; 255 | 256 | for (unsigned int i = 0; i < nr; i++) 257 | for (unsigned int j = rowStart[i]; j < rowEnd(i) && column[j] < i; j++) 258 | b[column[j]] += values[j] * x[i]; 259 | break; 260 | case UPPER_TRANGULAR: 261 | assert(0); /*TODO*/ 262 | break; 263 | } 264 | } 265 | 266 | /******************************************************************************************************************************/ 267 | 268 | void CholmodSparseMatrix::transposeMultiply(CholmodVector &x, CholmodVector &b) 269 | { 270 | for (unsigned int i = 0; i < nc; i++) 271 | b[i] = 0; 272 | for (unsigned int i = 0; i < nr; i++) 273 | for (unsigned int j = rowStart[i]; j < rowEnd(i); j++) 274 | b[column[j]] += values[j] * x[i]; 275 | } 276 | 277 | /******************************************************************************************************************************/ 278 | 279 | void CholmodSparseMatrix::zeroOutColumns(std::set& cols, int shift) 280 | { 281 | for (unsigned int i = 0; i < numNonzero; i++) 282 | if (cols.count(column[i] - shift) >= 1) 283 | values[i] = 0; 284 | } 285 | 286 | /******************************************************************************************************************************/ 287 | 288 | void CholmodSparseMatrix::copy(CholmodSparseMatrix& m) 289 | { 290 | reshape(m.nr, m.nc, m.capacity); 291 | // dest, src, size 292 | numNonzero = m.numNonzero; 293 | memcpy(values, m.values, m.numNonzero * sizeof(double)); 294 | memcpy(rowStart, m.rowStart, nr * sizeof(int)); 295 | memcpy(column, m.column, numNonzero * sizeof(int)); 296 | curLocation = m.curLocation; 297 | lastR = m.lastR; 298 | type = m.type; 299 | } 300 | 301 | /******************************************************************************************************************************/ 302 | 303 | void CholmodSparseMatrix::display(const char* var, FILE* out) const 304 | { 305 | bool first = true; 306 | int count = 0; 307 | fprintf(out,"I = ["); 308 | 309 | for (unsigned int i = 0; i < nr; i++) 310 | { 311 | for (unsigned int k = rowStart[i]; k < rowEnd(i); k++) { 312 | if (first) { 313 | fprintf(out,"%d", i+1); 314 | first = false; 315 | } else 316 | fprintf(out,", %d", i+1); 317 | 318 | count++; 319 | if (count == 30) { 320 | fprintf(out, " ... \n"); 321 | count = 0; 322 | } 323 | } 324 | } 325 | 326 | fprintf(out,"];\n"); 327 | first = true; 328 | count = 0; 329 | fprintf(out,"J = ["); 330 | 331 | for (unsigned int i = 0; i < nr; i++) 332 | { 333 | for (unsigned int k = rowStart[i]; k < rowEnd(i); k++) { 334 | if (first) { 335 | fprintf(out,"%d", column[k]+1); 336 | first = false; 337 | } else 338 | fprintf(out,", %d", column[k]+1); 339 | 340 | 341 | count++; 342 | if (count == 30) { 343 | fprintf(out, " ... \n"); 344 | count = 0; 345 | } 346 | } 347 | } 348 | 349 | fprintf(out,"];\n"); 350 | first = true; 351 | count = 0; 352 | fprintf(out,"S = ["); 353 | 354 | 355 | for (unsigned int i = 0; i < nr; i++) 356 | { 357 | for (unsigned int k = rowStart[i]; k < rowEnd(i); k++) { 358 | if (first) { 359 | fprintf(out,"%25.20e", values[k]); 360 | first = false; 361 | } else 362 | fprintf(out,", %25.20e", values[k]); 363 | 364 | count++; 365 | if (count == 10) { 366 | fprintf(out, " ... \n"); 367 | count = 0; 368 | } 369 | } 370 | } 371 | 372 | fprintf(out,"];\n"); 373 | fprintf(out,"%s = sparse(I,J,S,%d,%d);\n", var, numRows(), numCols()); 374 | } 375 | 376 | /******************************************************************************************************************************/ 377 | 378 | void CholmodSparseMatrix::getCholmodMatrix(cholmod_sparse& matrix) 379 | { 380 | rowStart[nr] = numNonzero; 381 | 382 | matrix.nrow = numCols(); // P is row-major, so cholmod thinks it's P* 383 | matrix.ncol = numRows(); 384 | matrix.nzmax = numNonzero; 385 | matrix.p = rowStart; 386 | matrix.i = column; 387 | matrix.x = values; 388 | matrix.z = NULL; 389 | matrix.itype = CHOLMOD_INT; 390 | matrix.xtype = CHOLMOD_REAL; 391 | matrix.dtype = CHOLMOD_DOUBLE; 392 | matrix.sorted = 1; 393 | matrix.packed = 1; 394 | matrix.nz = NULL; 395 | 396 | switch(type) { 397 | case ASSYMETRIC: 398 | matrix.stype = 0; 399 | break; 400 | case LOWER_TRIANGULAR: 401 | matrix.stype = 1; 402 | break; 403 | case UPPER_TRANGULAR: 404 | matrix.stype = -1; 405 | break; 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /utils/cholmod_matrix.h: -------------------------------------------------------------------------------- 1 | #ifndef SIMPLESPARSEMATRIX_H 2 | #define SIMPLESPARSEMATRIX_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | class CholmodVector; 13 | /******************************************************************************************************************************/ 14 | class CholmodSparseMatrix 15 | { 16 | public: 17 | 18 | enum Type { 19 | UPPER_TRANGULAR, 20 | LOWER_TRIANGULAR, 21 | ASSYMETRIC, 22 | }; 23 | 24 | CholmodSparseMatrix(CholmodSparseMatrix::Type type, int r, int c, int nz); 25 | CholmodSparseMatrix(CholmodSparseMatrix::Type type); 26 | 27 | ~CholmodSparseMatrix(); 28 | 29 | /********************************************************************/ 30 | 31 | void reshape(unsigned int r, unsigned int c, unsigned int cap); 32 | void setCapacity(unsigned int c); 33 | 34 | /********************************************************************/ 35 | 36 | void startMatrixFill(); 37 | double* addElement(unsigned int r, unsigned int c, double value); 38 | void addConstraint(const std::vector& rows, double alpha); 39 | 40 | /********************************************************************/ 41 | 42 | void multiply(CholmodSparseMatrix &m, CholmodSparseMatrix &result); 43 | void stack(CholmodSparseMatrix **matrices, unsigned int numMatrices, unsigned int *colShifts); 44 | void transpose(CholmodSparseMatrix &result); 45 | 46 | void multiply(CholmodVector &x, CholmodVector &b); 47 | void transposeMultiply(CholmodVector &x, CholmodVector &b); 48 | 49 | void zeroOutColumns(std::set& cols, int shift = 0); 50 | void copy(CholmodSparseMatrix& m); 51 | 52 | double infinityNorm(); 53 | CholmodSparseMatrix& operator =(const CholmodSparseMatrix& m); 54 | 55 | /********************************************************************/ 56 | unsigned int numRows() const {return nr;} 57 | unsigned int numCols() const {return nc;} 58 | unsigned int getCapacity() const { return capacity;} 59 | 60 | /********************************************************************/ 61 | void display(const char* var, FILE* out) const; 62 | 63 | void getCholmodMatrix(cholmod_sparse& matrix); 64 | private: 65 | unsigned int rowEnd(unsigned int i) const { return (i == nr-1)? numNonzero : rowStart[i+1]; } 66 | private: 67 | unsigned int numNonzero; 68 | unsigned int nc; 69 | unsigned int nr; 70 | double *values; 71 | unsigned int *rowStart; 72 | unsigned int *column; 73 | 74 | unsigned int curLocation; 75 | int lastR; 76 | 77 | Type type; 78 | 79 | unsigned int capacity; 80 | unsigned int rowCapacity; 81 | 82 | }; 83 | /******************************************************************************************************************************/ 84 | 85 | 86 | #endif // SIMPLESPARSEMATRIX_H 87 | -------------------------------------------------------------------------------- /utils/cholmod_vector.h: -------------------------------------------------------------------------------- 1 | #ifndef CHOLMOD_VECTOR_H 2 | #define CHOLMOD_VECTOR_H 3 | 4 | #include 5 | #include "cholmod_common.h" 6 | #include 7 | 8 | 9 | class CholmodVector 10 | { 11 | public: 12 | CholmodVector(unsigned int len) : 13 | values(cholmod_zeros(len, 1, CHOLMOD_REAL, cholmod_get_common())), cm(cholmod_get_common()) 14 | {} 15 | 16 | CholmodVector() : values(NULL), cm(cholmod_get_common()){} 17 | 18 | void resize(unsigned int newSize) 19 | { 20 | cholmod_free_dense(&values,cm); 21 | values = cholmod_zeros(newSize, 1, CHOLMOD_REAL, cm); 22 | } 23 | 24 | unsigned int size() const 25 | { 26 | return values->nrow; 27 | } 28 | 29 | void setData(cholmod_dense* new_values) 30 | { 31 | cholmod_free_dense(&values, cm); 32 | values = new_values; 33 | } 34 | 35 | void add(const CholmodVector &other) 36 | { 37 | double *values1 = getValues(); 38 | const double *values2 = other.getValues(); 39 | 40 | for (unsigned int i = 0 ; i < size() ;i++) 41 | values1[i] += values2[i]; 42 | } 43 | 44 | void sub(const CholmodVector &other) 45 | { 46 | double *values1 = getValues(); 47 | const double *values2 = other.getValues(); 48 | 49 | for (unsigned int i = 0 ; i < size() ;i++) 50 | values1[i] = values1[i] - values2[i]; 51 | } 52 | 53 | double& operator[] (int index) 54 | { 55 | return getValues()[index]; 56 | } 57 | 58 | const double& operator[] (int index) const 59 | { 60 | return getValues()[index]; 61 | } 62 | 63 | CholmodVector operator*(const double other) const 64 | { 65 | const double *values1 = getValues(); 66 | CholmodVector result(size()); 67 | 68 | for (unsigned int i = 0 ; i < size() ; i++) 69 | result[i] = values1[i] * other; 70 | 71 | return result; 72 | } 73 | 74 | 75 | void display(const char* var, FILE* file) 76 | { 77 | double *values1 = getValues(); 78 | 79 | fprintf(file, "%s = [", var); 80 | bool first = true; 81 | 82 | for (unsigned int i = 0 ; i < size() ; i++) { 83 | if (first) { 84 | first = false; 85 | fprintf(file, "%25.20e", values1[i]); 86 | } else 87 | fprintf(file, "; %25.20e", values1[i]); 88 | } 89 | 90 | fprintf(file, "];\n"); 91 | } 92 | 93 | operator cholmod_dense*() { return values; } 94 | 95 | double* getValues() { return (double*)values->x; } 96 | const double* getValues() const { return (double*)values->x; } 97 | 98 | ~CholmodVector() { cholmod_free_dense(&values,cm); } 99 | public: 100 | cholmod_dense* values; 101 | cholmod_common *cm; 102 | }; 103 | 104 | #endif 105 | -------------------------------------------------------------------------------- /utils/ffmpeg_encoder.cpp: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Adapted from https://code.google.com/p/qtffmpegwrapper/ 4 | // Modified to work with modern ffmpeg 5 | 6 | 7 | #include "ffmpeg_encoder.h" 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "utils.h" 13 | 14 | /******************************************************************************************************************************/ 15 | FFMpegEncoder::FFMpegEncoder(int FPS) : FPS(FPS) 16 | { 17 | ok=false; 18 | avFormatContext=0; 19 | avOutputFormat=0; 20 | avCodecCtx=0; 21 | avStream=0; 22 | avFrame=0; 23 | picture_buf=0; 24 | swsCtx=0; 25 | currrent_frame = 0; 26 | av_register_all(); 27 | swsCtx = NULL; 28 | } 29 | /******************************************************************************************************************************/ 30 | FFMpegEncoder::~FFMpegEncoder() 31 | { 32 | sws_freeContext(swsCtx); 33 | close(); 34 | } 35 | 36 | /******************************************************************************************************************************/ 37 | bool FFMpegEncoder::createFile(std::string filename, unsigned width,unsigned height) 38 | { 39 | // If we had an open video, close it. 40 | close(); 41 | 42 | Width=width; 43 | Height=height; 44 | fileName = filename; 45 | 46 | /* -----------------------------------------------------------------------------------*/ 47 | avOutputFormat = av_guess_format(NULL, fileName.c_str(), NULL); 48 | if (!avOutputFormat) return false; 49 | 50 | avFormatContext=avformat_alloc_context(); 51 | if(!avFormatContext) return false; 52 | 53 | avFormatContext->oformat = avOutputFormat; 54 | sprintf(avFormatContext->filename, "%s", fileName.c_str()); 55 | 56 | if (avio_open(&avFormatContext->pb, fileName.c_str(), AVIO_FLAG_WRITE) < 0) 57 | return false; 58 | 59 | /* -----------------------------------------------------------------------------------*/ 60 | avCodec = avcodec_find_encoder(CODEC_ID_H264); 61 | if (!avCodec) return false; 62 | 63 | 64 | avStream = avformat_new_stream(avFormatContext,avCodec); 65 | if(!avStream ) return false; 66 | 67 | avCodecCtx = avcodec_alloc_context3(avCodec); 68 | if (!avCodecCtx) return false; 69 | 70 | avCodecCtx->bit_rate = 9000000; 71 | avCodecCtx->width = width; 72 | avCodecCtx->height = height; 73 | avCodecCtx->time_base.num = 1; 74 | avCodecCtx->time_base.den = FPS; 75 | avCodecCtx->gop_size = 250; /* emit one intra frame every ten frames */ 76 | avCodecCtx->max_b_frames=1; 77 | avCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; 78 | av_opt_set(avCodecCtx->priv_data, "preset", "fast", 0); 79 | 80 | /* open it */ 81 | if (avcodec_open2(avCodecCtx, avCodec, NULL) < 0) return false; 82 | 83 | avStream->codec = avCodecCtx; 84 | 85 | /* -----------------------------------------------------------------------------------*/ 86 | avformat_write_header(avFormatContext,NULL); 87 | /* -----------------------------------------------------------------------------------*/ 88 | 89 | avFrame = avcodec_alloc_frame(); 90 | if(avFrame==0) return false; 91 | 92 | int size = avpicture_get_size(avCodecCtx->pix_fmt, avCodecCtx->width, avCodecCtx->height); 93 | picture_buf = new uint8_t[size]; 94 | if(picture_buf==0) return false; 95 | 96 | avpicture_fill((AVPicture *)avFrame, picture_buf,avCodecCtx->pix_fmt, avCodecCtx->width, avCodecCtx->height); 97 | 98 | swsCtx = sws_getContext(Width,Height, 99 | PIX_FMT_BGRA,Width,Height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, NULL, NULL, NULL); 100 | if (swsCtx == NULL) return false; 101 | 102 | ok=true; 103 | currrent_frame = 0; 104 | return true; 105 | } 106 | 107 | 108 | /******************************************************************************************************************************/ 109 | bool FFMpegEncoder::encodeImageBGRA(uint8_t* image) 110 | { 111 | if(!ok) return false; 112 | 113 | TimeMeasurment t; 114 | 115 | swsCtx = sws_getCachedContext(swsCtx,Width,Height, 116 | PIX_FMT_BGRA,Width,Height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, NULL, NULL, NULL); 117 | if (swsCtx == NULL) return false; 118 | 119 | 120 | uint8_t* srcplane[4] = {image,NULL,NULL,NULL}; 121 | int srcstride[4] = {(int)(Width*4),0,0,0}; 122 | 123 | sws_scale(swsCtx, srcplane, srcstride,0, Height, avFrame->data, avFrame->linesize); 124 | avFrame->pts = currrent_frame++; 125 | 126 | printf("Took %f msec to convert the image\n", t.measure_msec()); 127 | 128 | AVPacket p = {0}; 129 | av_init_packet(&p); 130 | 131 | p.stream_index = avStream->index; 132 | 133 | int got_packet; 134 | if (avcodec_encode_video2(avStream->codec, &p, avFrame, &got_packet) < 0) 135 | return false; 136 | 137 | printf("Took %f msec to encode the image\n", t.measure_msec()); 138 | 139 | if (!got_packet) 140 | return true; 141 | 142 | av_interleaved_write_frame (avFormatContext, &p); 143 | printf("Took %f msec to write the image\n", t.measure_msec()); 144 | 145 | av_free_packet(&p); 146 | return true; 147 | } 148 | 149 | /******************************************************************************************************************************/ 150 | bool FFMpegEncoder::close() 151 | { 152 | if(!ok) return false; 153 | 154 | AVPacket pkt = { 0 }; 155 | av_init_packet(&pkt); 156 | 157 | int got_packet; 158 | 159 | do { 160 | if (avcodec_encode_video2(avStream->codec, &pkt, NULL, &got_packet) < 0) 161 | return false; 162 | if (got_packet) av_write_frame (avFormatContext, &pkt); 163 | av_free_packet(&pkt); 164 | } while(got_packet); 165 | 166 | av_write_trailer(avFormatContext); 167 | 168 | avcodec_close(avStream->codec); 169 | avCodecCtx=0; 170 | avCodec = 0; 171 | 172 | avformat_close_input(&avFormatContext); 173 | avFormatContext=0; 174 | avOutputFormat=0; 175 | avStream=0; 176 | 177 | delete[] picture_buf; 178 | picture_buf=0; 179 | av_free(avFrame); 180 | avFrame=0; 181 | 182 | sws_freeContext(swsCtx); 183 | swsCtx=0; 184 | 185 | ok=false; 186 | return true; 187 | } 188 | 189 | /******************************************************************************************************************************/ 190 | -------------------------------------------------------------------------------- /utils/ffmpeg_encoder.h: -------------------------------------------------------------------------------- 1 | #ifndef __QVideoEncoder_H 2 | #define __QVideoEncoder_H 3 | 4 | // Adapted from https://code.google.com/p/qtffmpegwrapper/ 5 | // Modified to work with modern ffmpeg 6 | 7 | extern "C" { 8 | #include "libavformat/avformat.h" 9 | #include "libavformat/avio.h" 10 | #include "libavcodec/avcodec.h" 11 | #include "libavutil/mathematics.h" 12 | #include "libavutil/rational.h" 13 | #include "libavutil/dict.h" 14 | #include "libavutil/avstring.h" 15 | #include "libavutil/opt.h" 16 | #include "libavutil/avconfig.h" 17 | #include "libswscale/swscale.h" 18 | } 19 | 20 | #include 21 | 22 | class FFMpegEncoder 23 | { 24 | public: 25 | 26 | FFMpegEncoder(int FPS); 27 | virtual ~FFMpegEncoder(); 28 | 29 | bool createFile(std::string filename,unsigned width,unsigned height); 30 | bool encodeImageBGRA(uint8_t* image); 31 | bool close(); 32 | 33 | double getFrameTimeMsec() { return (1.0 / FPS) * 1000; } 34 | private: 35 | unsigned Width,Height; 36 | bool ok; 37 | 38 | // FFmpeg stuff 39 | AVFormatContext *avFormatContext; 40 | AVOutputFormat *avOutputFormat; 41 | AVCodecContext *avCodecCtx; 42 | AVStream *avStream; 43 | AVCodec *avCodec; 44 | // Frame data 45 | AVFrame *avFrame; 46 | uint8_t *picture_buf; 47 | // Conversion 48 | SwsContext *swsCtx; 49 | std::string fileName; 50 | 51 | int FPS; 52 | int currrent_frame; 53 | }; 54 | 55 | #endif // QVideoEncoder_H 56 | -------------------------------------------------------------------------------- /utils/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "utils.h" 5 | 6 | /******************************************************************************************************************************/ 7 | 8 | bool ends_with(std::string const & file, std::string const & ending) 9 | { 10 | std::string filename_lower = file; 11 | std::transform(file.begin(), file.end(), filename_lower.begin(), ::tolower); 12 | 13 | if (ending.size() > filename_lower.size()) return false; 14 | return std::equal(ending.rbegin(), ending.rend(), filename_lower.rbegin()); 15 | } 16 | /******************************************************************************************************************************/ 17 | 18 | 19 | static double planeSign (Point2 p1, Point2 p2, Point2 p3) 20 | { 21 | return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); 22 | } 23 | /******************************************************************************************************************************/ 24 | 25 | bool PointInTriangle (Point2 pt, Point2 v1, Point2 v2, Point2 v3) 26 | { 27 | bool b1, b2, b3; 28 | b1 = planeSign(pt, v1, v2) < 0.0f; 29 | b2 = planeSign(pt, v2, v3) < 0.0f; 30 | b3 = planeSign(pt, v3, v1) < 0.0f; 31 | return ((b1 == b2) && (b2 == b3)); 32 | } 33 | /******************************************************************************************************************************/ 34 | 35 | double edgeDistance(Point2 p1, Point2 p2, Point2 p) 36 | { 37 | double x1 = p1.x; 38 | double x2 = p2.x; 39 | double y1 = p1.y; 40 | double y2 = p2.y; 41 | 42 | double x0 = p.x; 43 | double y0 = p.y; 44 | 45 | double den = fabs((y2 - y1)*x0 - (x2-x1)*y0 + x2*y1-y2*x1); 46 | double num = sqrt((y2-y1)*(y2-y1) + (x2-x1)*(x2-x1)); 47 | 48 | 49 | double linedist = den / num; 50 | 51 | double p1_dist = p1.distance(p); 52 | double p2_dist = p2.distance(p); 53 | double edge_len = p1.distance(p2); 54 | 55 | if (p1_dist > edge_len) 56 | return std::numeric_limits::infinity(); 57 | 58 | if (p2_dist > edge_len) 59 | return std::numeric_limits::infinity(); 60 | 61 | return linedist; 62 | } 63 | 64 | /******************************************************************************************************************************/ 65 | 66 | 67 | void debug_printf(const char* string, ...) 68 | { 69 | #ifdef __DEBUG_VERBOSE__ 70 | va_list list; 71 | va_start(list,string); 72 | vprintf(string,list); 73 | #endif 74 | } 75 | 76 | /******************************************************************************************************************************/ 77 | 78 | std::string printTime(int time) 79 | { 80 | int fraction = (time % 1000); 81 | time /= 1000; 82 | int seconds = time % 60; 83 | time /= 60; 84 | int minutes = time; 85 | 86 | char buffer[50]; 87 | sprintf(buffer, "%02d:%02d.%03d", minutes, seconds,fraction); 88 | return buffer; 89 | } 90 | /******************************************************************************************************************************/ 91 | int getTime(std::string time) 92 | { 93 | int minutes, seconds, fraction; 94 | 95 | if (sscanf(time.c_str(), "%02d:%02d.%03d", &minutes, &seconds,&fraction) < 3) 96 | return -1; 97 | 98 | int result = minutes * 60; 99 | result += seconds; 100 | result *= 1000; 101 | result += fraction; 102 | return result; 103 | } 104 | 105 | TimeMeasurment::TimeMeasurment() 106 | { 107 | timer.start(); 108 | } 109 | 110 | double TimeMeasurment::measure_msec() 111 | { 112 | double retval = (double)timer.nsecsElapsed() / 1000000.0; 113 | timer.restart(); 114 | return retval; 115 | } 116 | -------------------------------------------------------------------------------- /utils/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "vector2d.h" 9 | #include 10 | #include 11 | 12 | typedef int Vertex; 13 | #define connect_(a,b,c,d) connect(a, SIGNAL(b), c, SLOT(d)) 14 | 15 | /***********************************************************************************************/ 16 | 17 | class TimeMeasurment 18 | { 19 | QElapsedTimer timer; 20 | public: 21 | TimeMeasurment(); 22 | double measure_msec(); 23 | }; 24 | 25 | /***********************************************************************************************/ 26 | struct Face 27 | { 28 | Face() {} 29 | Face(Vertex v0, Vertex v1, Vertex v2) 30 | { 31 | f[0] = v0; 32 | f[1] = v1; 33 | f[2] = v2; 34 | } 35 | 36 | Vertex f[3]; 37 | Vertex &operator[](int i) {return f[i];} 38 | Vertex a() { return f[0]; } 39 | Vertex b() { return f[1]; } 40 | Vertex c() { return f[2]; } 41 | }; 42 | 43 | /*****************************************************************************************************/ 44 | struct OrderedEdge 45 | { 46 | OrderedEdge(Vertex v0, Vertex v1) : v0(v0),v1(v1) {} 47 | OrderedEdge() {} 48 | 49 | bool operator<(const OrderedEdge& other) const 50 | { 51 | if (v0 != other.v0) 52 | return v0 < other.v0; 53 | return v1 < other.v1; 54 | } 55 | 56 | bool operator==(const OrderedEdge& other) const 57 | { 58 | return (v0 == other.v0 && v1 == other.v1); 59 | } 60 | 61 | Vertex v0; 62 | Vertex v1; 63 | }; 64 | 65 | /*****************************************************************************************************/ 66 | struct Edge : public OrderedEdge 67 | { 68 | /* Edged are unordered, so sort endpoints*/ 69 | Edge(Vertex v0new,Vertex v1new) : OrderedEdge(v0new,v1new) 70 | { 71 | if (v1 > v0) std::swap(v0,v1); 72 | } 73 | }; 74 | 75 | /*****************************************************************************************************/ 76 | /* angle formed by p1 (and points sorted counter-clockwise, so order matters!!!) */ 77 | struct Angle 78 | { 79 | Angle(Vertex p0,Vertex p1,Vertex p2) : p0(p0),p1(p1),p2(p2) 80 | {} 81 | 82 | bool operator<(const Angle& other) const 83 | { 84 | if (p0 != other.p0) 85 | return p0 < other.p0; 86 | if (p1 != other.p1) 87 | return p1 < other.p1; 88 | return p2 < other.p2; 89 | } 90 | 91 | bool operator==(const Angle& other) const 92 | { 93 | return (p0 == other.p0 && p1 == other.p1 && p2 == other.p2); 94 | } 95 | 96 | 97 | Vertex p0; 98 | Vertex p1; 99 | Vertex p2; 100 | }; 101 | 102 | /***********************************************************************************************/ 103 | class BBOX 104 | { 105 | public: 106 | Point2 minP; 107 | Point2 maxP; 108 | 109 | BBOX() 110 | { 111 | minP = Vector2(std::numeric_limits::max(), std::numeric_limits::max()); 112 | maxP = Vector2(std::numeric_limits::min(), std::numeric_limits::min()); 113 | } 114 | 115 | BBOX(const std::vector &vertices) 116 | { 117 | minP = Vector2(std::numeric_limits::max(), std::numeric_limits::max()); 118 | maxP = Vector2(std::numeric_limits::min(), std::numeric_limits::min()); 119 | 120 | for (auto iter = vertices.begin() ; iter != vertices.end() ; iter++) 121 | { 122 | minP = minP.min(*iter); 123 | maxP = maxP.max(*iter); 124 | } 125 | } 126 | 127 | Point2 center() { 128 | return (minP + maxP) /2.0; 129 | } 130 | 131 | double width() { return maxP.x - minP.x; } 132 | double height() { return maxP.y - minP.y; } 133 | 134 | void operator+=(const BBOX& other) 135 | { 136 | minP = minP.min(other.minP); 137 | maxP = maxP.max(other.maxP); 138 | } 139 | 140 | }; 141 | 142 | /***********************************************************************************************/ 143 | class CmdStream 144 | { 145 | public: 146 | CmdStream(const CmdStream& other) : stream(other.stream), end(other.end), shared(true) {} 147 | 148 | ~CmdStream() 149 | { 150 | if (!shared) free(stream); 151 | end = NULL; 152 | } 153 | 154 | uint8_t byte () { 155 | uint8_t retval = *(uint8_t*) (stream); 156 | stream++; 157 | return retval; 158 | } 159 | 160 | uint16_t word () { 161 | uint16_t retval = *(uint16_t*) (stream); 162 | stream += 2; 163 | return retval; 164 | } 165 | 166 | uint32_t dword() { 167 | uint32_t retval = *(uint32_t*) (stream); 168 | stream += 4; 169 | return retval; 170 | } 171 | 172 | bool ended() { 173 | return stream == end; 174 | } 175 | 176 | int getSize() { return end - stream; } 177 | 178 | private: 179 | CmdStream() {} 180 | bool operator=(const CmdStream &other); 181 | private: 182 | uint8_t* stream; 183 | uint8_t* end; 184 | bool shared; 185 | friend class CmdStreamBuilder; 186 | }; 187 | 188 | /***********************************************************************************************/ 189 | 190 | class CmdStreamBuilder 191 | { 192 | std::vector cmd_stream; 193 | public: 194 | void push_byte(uint8_t data) { 195 | cmd_stream.push_back(data); 196 | } 197 | 198 | void push_word(uint16_t data) { 199 | cmd_stream.push_back(data & 0xFF); 200 | cmd_stream.push_back(data >> 8); 201 | } 202 | 203 | void push_dword(uint32_t data) { 204 | cmd_stream.push_back((data >> 0) & 0xFF ); 205 | cmd_stream.push_back((data >> 8) & 0xFF ); 206 | cmd_stream.push_back((data >> 16) & 0xFF ); 207 | cmd_stream.push_back((data >> 24) & 0xFF ); 208 | } 209 | 210 | CmdStream* get_stream() 211 | { 212 | CmdStream *retval = new CmdStream(); 213 | 214 | int size = cmd_stream.size(); 215 | retval->stream = (uint8_t*)malloc(size); 216 | retval->end = retval->stream + size; 217 | retval->shared = false; 218 | 219 | int i = 0; 220 | for (auto iter = cmd_stream.begin() ; iter != cmd_stream.end() ; iter++,i++) { 221 | retval->stream[i] = *iter; 222 | } 223 | 224 | return retval; 225 | } 226 | }; 227 | 228 | /***********************************************************************************************/ 229 | 230 | typedef unsigned int TmpMemAdddress; 231 | class TmpMemAllocator 232 | { 233 | public: 234 | 235 | TmpMemAllocator() { nextVarAddress = 0; } 236 | 237 | TmpMemAdddress getNewVar(int size = 1) 238 | { 239 | TmpMemAdddress retval = nextVarAddress; 240 | nextVarAddress += size; 241 | return retval; 242 | } 243 | 244 | int getSize() { return nextVarAddress; } 245 | 246 | bool validAddress(TmpMemAdddress address) 247 | { 248 | assert(address <= nextVarAddress); 249 | return (nextVarAddress - address) < 0xEFFF; 250 | } 251 | private: 252 | TmpMemAdddress nextVarAddress; 253 | }; 254 | 255 | /***********************************************************************************************/ 256 | 257 | bool ends_with(std::string const & value, std::string const & ending); 258 | bool PointInTriangle (Point2 pt, Point2 v1, Point2 v2, Point2 v3); 259 | double edgeDistance(Point2 p1, Point2 p2, Point2 p); 260 | void debug_printf(const char* string, ...); 261 | std::string printTime(int time); 262 | int getTime(std::string time); 263 | 264 | #endif 265 | -------------------------------------------------------------------------------- /utils/vector2d.cpp: -------------------------------------------------------------------------------- 1 | #include "vector2d.h" 2 | #include 3 | 4 | template 5 | Vector2D& Vector2D::rotate(T angle) { // counterclockwise 6 | T s = sin(angle); 7 | T c = cos(angle); 8 | 9 | T nx = c * x - s * y; 10 | T ny = s * x + c * y; 11 | 12 | x = nx; 13 | y = ny; 14 | 15 | return (*this); 16 | } 17 | 18 | template 19 | T rotationAngle(Vector2D v1, Vector2D v2) { 20 | // Apparently atan2 doesn't care about unit-length vectors 21 | T cosine = v1.dot(v2); 22 | T sine = v1.cross(v2); 23 | T angle = atan2(sine, cosine); // atan2 does sine and then cosine 24 | 25 | //qWarning("Vec 1: %g %g", v1.x, v1.y); 26 | //qWarning("Vec 2: %g %g", v2.x, v2.y); 27 | //qWarning("Original angle: %g (%g,%g)", angle/M_PI, cosine, sine); 28 | 29 | return (angle<0)? angle+2*M_PI : angle; // atan2 does [-pi, pi] 30 | } 31 | 32 | template class Vector2D; 33 | template class Vector2D; 34 | template class Point2D; 35 | template class Point2D; 36 | template double rotationAngle(Vector2D v1, Vector2D v2); 37 | template float rotationAngle(Vector2D v1, Vector2D v2); 38 | -------------------------------------------------------------------------------- /utils/vector2d.h: -------------------------------------------------------------------------------- 1 | #ifndef VECTOR2D_H 2 | #define VECTOR2D_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | // adapted from http://www.terathon.com/code/vector2d.html 9 | 10 | template 11 | class Vector2D { 12 | public: 13 | T x; 14 | T y; 15 | 16 | void print(const char *tag = "") const { 17 | printf("%s %g %g\n", tag, x, y); 18 | } 19 | 20 | QPointF toQPoint() const { 21 | return QPointF(x,y); 22 | } 23 | 24 | T cross(const Vector2D &v) const { 25 | return x*v.y - v.x*y; 26 | } 27 | 28 | T norm() const { return sqrtf(normSquared()); } 29 | T normSquared() const { return x*x+y*y; } 30 | 31 | Vector2D() : x(0), y(0) {} 32 | 33 | Vector2D(std::complex v) : x(std::real(v)), y(std::imag(v)) {} 34 | 35 | Vector2D(QPointF p) : x(p.x()), y(p.y()) {} 36 | 37 | Vector2D(T r, T s) { 38 | x = r; 39 | y = s; 40 | } 41 | 42 | Vector2D& set(T r, T s) { 43 | x = r; 44 | y = s; 45 | return (*this); 46 | } 47 | 48 | T& operator [](long k) { 49 | return ((&x)[k]); 50 | } 51 | 52 | const T& operator [](long k) const { 53 | return ((&x)[k]); 54 | } 55 | 56 | Vector2D& operator +=(const Vector2D& v) { 57 | x += v.x; 58 | y += v.y; 59 | return (*this); 60 | } 61 | 62 | Vector2D& operator -=(const Vector2D& v) { 63 | x -= v.x; 64 | y -= v.y; 65 | return (*this); 66 | } 67 | 68 | Vector2D& operator *=(T t) { 69 | x *= t; 70 | y *= t; 71 | return (*this); 72 | } 73 | 74 | Vector2D& operator /=(T t) { 75 | T f = 1.0F / t; 76 | x *= f; 77 | y *= f; 78 | return (*this); 79 | } 80 | 81 | Vector2D& operator &=(const Vector2D& v) { 82 | x *= v.x; 83 | y *= v.y; 84 | return (*this); 85 | } 86 | 87 | Vector2D operator -() const { 88 | return (Vector2D(-x, -y)); 89 | } 90 | 91 | Vector2D operator +(const Vector2D& v) const { 92 | return (Vector2D(x + v.x, y + v.y)); 93 | } 94 | 95 | Vector2D operator -(const Vector2D& v) const { 96 | return (Vector2D(x - v.x, y - v.y)); 97 | } 98 | 99 | Vector2D operator *(T t) const { 100 | return (Vector2D(x * t, y * t)); 101 | } 102 | 103 | Vector2D operator /(T t) const { 104 | T f = 1.0F / t; 105 | return (Vector2D(x * f, y * f)); 106 | } 107 | 108 | T operator *(const Vector2D& v) const { 109 | return (x * v.x + y * v.y); 110 | } 111 | 112 | T dot(const Vector2D& v) const { 113 | return (*this)*v; 114 | } 115 | 116 | Vector2D operator &(const Vector2D& v) const { 117 | return (Vector2D(x * v.x, y * v.y)); 118 | } 119 | 120 | bool operator ==(const Vector2D& v) const { 121 | return ((x == v.x) && (y == v.y)); 122 | } 123 | 124 | bool operator !=(const Vector2D& v) const { 125 | return ((x != v.x) || (y != v.y)); 126 | } 127 | 128 | Vector2D& normalize(void) { 129 | return (*this /= sqrtf(x * x + y * y)); 130 | } 131 | 132 | Vector2D& rotate(T angle); 133 | 134 | std::complex toComplex() { return std::complex(x,y); } 135 | 136 | Vector2D min(const Vector2D &other) const { 137 | T minX = std::min(x,other.x); 138 | T minY = std::min(y,other.y); 139 | return Vector2D(minX,minY); 140 | } 141 | 142 | Vector2D max(const Vector2D &other) const { 143 | T minX = std::max(x,other.x); 144 | T minY = std::max(y,other.y); 145 | return Vector2D(minX,minY); 146 | } 147 | 148 | }; 149 | 150 | template 151 | T rotationAngle(Vector2D v1, Vector2D v2); 152 | 153 | template 154 | class Point2D : public Vector2D { 155 | public: 156 | 157 | Point2D() : Vector2D(0,0) {} 158 | 159 | Point2D(T r, T s) : Vector2D(r, s) {} 160 | 161 | Point2D(std::complex v) : Vector2D(v) {} 162 | 163 | Point2D& operator =(const Vector2D& v) { 164 | this->x = v.x; 165 | this->y = v.y; 166 | return (*this); 167 | } 168 | 169 | Point2D& operator *=(T t) { 170 | this->x *= t; 171 | this->y *= t; 172 | return (*this); 173 | } 174 | 175 | Point2D& operator /=(T t) { 176 | T f = T(1.0) / t; 177 | this-> x *= f; 178 | this->y *= f; 179 | return (*this); 180 | } 181 | 182 | Point2D operator -() const { 183 | return (Point2D(-this->x, -this->y)); 184 | } 185 | 186 | Point2D operator +(const Vector2D& v) const { 187 | return (Point2D(this->x + v.x, this->y + v.y)); 188 | } 189 | 190 | Point2D operator -(const Vector2D& v) const { 191 | return (Point2D(this->x - v.x, this->y - v.y)); 192 | } 193 | 194 | Vector2D operator -(const Point2D& p) const { 195 | return (Vector2D(this->x - p.x, this->y - p.y)); 196 | } 197 | 198 | Point2D operator *(T t) const { 199 | return (Point2D(this->x * t, this->y * t)); 200 | } 201 | 202 | Point2D operator /(T t) const { 203 | T f = T(1.0) / t; 204 | return (Point2D(this->x * f, this->y * f)); 205 | } 206 | 207 | T distance(Point2D p2) const { 208 | return (*this-p2).norm(); 209 | } 210 | 211 | T distanceSquared(Point2D p2) const { 212 | return (*this-p2).normSquared(); 213 | } 214 | }; 215 | 216 | template 217 | inline Vector2D operator *(T t, const Vector2D& v) { 218 | return (Vector2D(t * v.x, t * v.y)); 219 | } 220 | 221 | template 222 | inline Point2D operator *(T t, const Point2D& p) { 223 | return (Point2D(t * p.x, t * p.y)); 224 | } 225 | 226 | typedef Vector2D Vector2; 227 | typedef Point2D Point2; 228 | 229 | #endif // Vector2D_H 230 | --------------------------------------------------------------------------------