├── .gitignore ├── CMakeLists.txt ├── Qt3DViewer.cpp ├── Qt3DViewer.h ├── Qt3DViewer.qrc ├── Qt3DViewer.ui ├── README.md ├── Resources └── images │ └── importMesh.png ├── main.cpp ├── openmeshApps ├── MeshViewerWidget.cpp ├── MeshViewerWidget.h ├── MeshViewerWidgetT.h ├── MeshViewerWidgetT_impl.h ├── QGLViewerWidget.cpp └── QGLViewerWidget.h └── screenshot └── Q3DViewer.png /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/qt,windows,c++,visualstudio 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=qt,windows,c++,visualstudio 4 | 5 | ### C++ ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | ### Qt ### 40 | # C++ objects and libs 41 | *.so.* 42 | 43 | # Qt-es 44 | object_script.*.Release 45 | object_script.*.Debug 46 | *_plugin_import.cpp 47 | /.qmake.cache 48 | /.qmake.stash 49 | *.pro.user 50 | *.pro.user.* 51 | *.qbs.user 52 | *.qbs.user.* 53 | *.moc 54 | moc_*.cpp 55 | moc_*.h 56 | qrc_*.cpp 57 | ui_*.h 58 | *.qmlc 59 | *.jsc 60 | Makefile* 61 | *build-* 62 | *.qm 63 | *.prl 64 | 65 | # Qt unit tests 66 | target_wrapper.* 67 | 68 | # QtCreator 69 | *.autosave 70 | 71 | # QtCreator Qml 72 | *.qmlproject.user 73 | *.qmlproject.user.* 74 | 75 | # QtCreator CMake 76 | CMakeLists.txt.user* 77 | 78 | # QtCreator 4.8< compilation database 79 | compile_commands.json 80 | 81 | # QtCreator local machine specific files for imported projects 82 | *creator.user* 83 | 84 | *_qmlcache.qrc 85 | 86 | ### Windows ### 87 | # Windows thumbnail cache files 88 | Thumbs.db 89 | Thumbs.db:encryptable 90 | ehthumbs.db 91 | ehthumbs_vista.db 92 | 93 | # Dump file 94 | *.stackdump 95 | 96 | # Folder config file 97 | [Dd]esktop.ini 98 | 99 | # Recycle Bin used on file shares 100 | $RECYCLE.BIN/ 101 | 102 | # Windows Installer files 103 | *.cab 104 | *.msi 105 | *.msix 106 | *.msm 107 | *.msp 108 | 109 | # Windows shortcuts 110 | *.lnk 111 | 112 | ### VisualStudio ### 113 | ## Ignore Visual Studio temporary files, build results, and 114 | ## files generated by popular Visual Studio add-ons. 115 | ## 116 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 117 | 118 | # User-specific files 119 | *.rsuser 120 | *.suo 121 | *.user 122 | *.userosscache 123 | *.sln.docstates 124 | 125 | # User-specific files (MonoDevelop/Xamarin Studio) 126 | *.userprefs 127 | 128 | # Mono auto generated files 129 | mono_crash.* 130 | 131 | # Build results 132 | [Dd]ebug/ 133 | [Dd]ebugPublic/ 134 | [Rr]elease/ 135 | [Rr]eleases/ 136 | x64/ 137 | x86/ 138 | [Ww][Ii][Nn]32/ 139 | [Aa][Rr][Mm]/ 140 | [Aa][Rr][Mm]64/ 141 | bld/ 142 | [Bb]in/ 143 | [Oo]bj/ 144 | [Ll]og/ 145 | [Ll]ogs/ 146 | 147 | # Visual Studio 2015/2017 cache/options directory 148 | .vs/ 149 | # Uncomment if you have tasks that create the project's static files in wwwroot 150 | #wwwroot/ 151 | 152 | # Visual Studio 2017 auto generated files 153 | Generated\ Files/ 154 | 155 | # MSTest test Results 156 | [Tt]est[Rr]esult*/ 157 | [Bb]uild[Ll]og.* 158 | 159 | # NUnit 160 | *.VisualState.xml 161 | TestResult.xml 162 | nunit-*.xml 163 | 164 | # Build Results of an ATL Project 165 | [Dd]ebugPS/ 166 | [Rr]eleasePS/ 167 | dlldata.c 168 | 169 | # Benchmark Results 170 | BenchmarkDotNet.Artifacts/ 171 | 172 | # .NET Core 173 | project.lock.json 174 | project.fragment.lock.json 175 | artifacts/ 176 | 177 | # ASP.NET Scaffolding 178 | ScaffoldingReadMe.txt 179 | 180 | # StyleCop 181 | StyleCopReport.xml 182 | 183 | # Files built by Visual Studio 184 | *_i.c 185 | *_p.c 186 | *_h.h 187 | *.ilk 188 | *.meta 189 | *.iobj 190 | *.pdb 191 | *.ipdb 192 | *.pgc 193 | *.pgd 194 | *.rsp 195 | *.sbr 196 | *.tlb 197 | *.tli 198 | *.tlh 199 | *.tmp 200 | *.tmp_proj 201 | *_wpftmp.csproj 202 | *.log 203 | *.tlog 204 | *.vspscc 205 | *.vssscc 206 | .builds 207 | *.pidb 208 | *.svclog 209 | *.scc 210 | 211 | # Chutzpah Test files 212 | _Chutzpah* 213 | 214 | # Visual C++ cache files 215 | ipch/ 216 | *.aps 217 | *.ncb 218 | *.opendb 219 | *.opensdf 220 | *.sdf 221 | *.cachefile 222 | *.VC.db 223 | *.VC.VC.opendb 224 | 225 | # Visual Studio profiler 226 | *.psess 227 | *.vsp 228 | *.vspx 229 | *.sap 230 | 231 | # Visual Studio Trace Files 232 | *.e2e 233 | 234 | # TFS 2012 Local Workspace 235 | $tf/ 236 | 237 | # Guidance Automation Toolkit 238 | *.gpState 239 | 240 | # ReSharper is a .NET coding add-in 241 | _ReSharper*/ 242 | *.[Rr]e[Ss]harper 243 | *.DotSettings.user 244 | 245 | # TeamCity is a build add-in 246 | _TeamCity* 247 | 248 | # DotCover is a Code Coverage Tool 249 | *.dotCover 250 | 251 | # AxoCover is a Code Coverage Tool 252 | .axoCover/* 253 | !.axoCover/settings.json 254 | 255 | # Coverlet is a free, cross platform Code Coverage Tool 256 | coverage*.json 257 | coverage*.xml 258 | coverage*.info 259 | 260 | # Visual Studio code coverage results 261 | *.coverage 262 | *.coveragexml 263 | 264 | # NCrunch 265 | _NCrunch_* 266 | .*crunch*.local.xml 267 | nCrunchTemp_* 268 | 269 | # MightyMoose 270 | *.mm.* 271 | AutoTest.Net/ 272 | 273 | # Web workbench (sass) 274 | .sass-cache/ 275 | 276 | # Installshield output folder 277 | [Ee]xpress/ 278 | 279 | # DocProject is a documentation generator add-in 280 | DocProject/buildhelp/ 281 | DocProject/Help/*.HxT 282 | DocProject/Help/*.HxC 283 | DocProject/Help/*.hhc 284 | DocProject/Help/*.hhk 285 | DocProject/Help/*.hhp 286 | DocProject/Help/Html2 287 | DocProject/Help/html 288 | 289 | # Click-Once directory 290 | publish/ 291 | 292 | # Publish Web Output 293 | *.[Pp]ublish.xml 294 | *.azurePubxml 295 | # Note: Comment the next line if you want to checkin your web deploy settings, 296 | # but database connection strings (with potential passwords) will be unencrypted 297 | *.pubxml 298 | *.publishproj 299 | 300 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 301 | # checkin your Azure Web App publish settings, but sensitive information contained 302 | # in these scripts will be unencrypted 303 | PublishScripts/ 304 | 305 | # NuGet Packages 306 | *.nupkg 307 | # NuGet Symbol Packages 308 | *.snupkg 309 | # The packages folder can be ignored because of Package Restore 310 | **/[Pp]ackages/* 311 | # except build/, which is used as an MSBuild target. 312 | !**/[Pp]ackages/build/ 313 | # Uncomment if necessary however generally it will be regenerated when needed 314 | #!**/[Pp]ackages/repositories.config 315 | # NuGet v3's project.json files produces more ignorable files 316 | *.nuget.props 317 | *.nuget.targets 318 | 319 | # Nuget personal access tokens and Credentials 320 | nuget.config 321 | 322 | # Microsoft Azure Build Output 323 | csx/ 324 | *.build.csdef 325 | 326 | # Microsoft Azure Emulator 327 | ecf/ 328 | rcf/ 329 | 330 | # Windows Store app package directories and files 331 | AppPackages/ 332 | BundleArtifacts/ 333 | Package.StoreAssociation.xml 334 | _pkginfo.txt 335 | *.appx 336 | *.appxbundle 337 | *.appxupload 338 | 339 | # Visual Studio cache files 340 | # files ending in .cache can be ignored 341 | *.[Cc]ache 342 | # but keep track of directories ending in .cache 343 | !?*.[Cc]ache/ 344 | 345 | # Others 346 | ClientBin/ 347 | ~$* 348 | *~ 349 | *.dbmdl 350 | *.dbproj.schemaview 351 | *.jfm 352 | *.pfx 353 | *.publishsettings 354 | orleans.codegen.cs 355 | 356 | # Including strong name files can present a security risk 357 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 358 | #*.snk 359 | 360 | # Since there are multiple workflows, uncomment next line to ignore bower_components 361 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 362 | #bower_components/ 363 | 364 | # RIA/Silverlight projects 365 | Generated_Code/ 366 | 367 | # Backup & report files from converting an old project file 368 | # to a newer Visual Studio version. Backup files are not needed, 369 | # because we have git ;-) 370 | _UpgradeReport_Files/ 371 | Backup*/ 372 | UpgradeLog*.XML 373 | UpgradeLog*.htm 374 | ServiceFabricBackup/ 375 | *.rptproj.bak 376 | 377 | # SQL Server files 378 | *.mdf 379 | *.ldf 380 | *.ndf 381 | 382 | # Business Intelligence projects 383 | *.rdl.data 384 | *.bim.layout 385 | *.bim_*.settings 386 | *.rptproj.rsuser 387 | *- [Bb]ackup.rdl 388 | *- [Bb]ackup ([0-9]).rdl 389 | *- [Bb]ackup ([0-9][0-9]).rdl 390 | 391 | # Microsoft Fakes 392 | FakesAssemblies/ 393 | 394 | # GhostDoc plugin setting file 395 | *.GhostDoc.xml 396 | 397 | # Node.js Tools for Visual Studio 398 | .ntvs_analysis.dat 399 | node_modules/ 400 | 401 | # Visual Studio 6 build log 402 | *.plg 403 | 404 | # Visual Studio 6 workspace options file 405 | *.opt 406 | 407 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 408 | *.vbw 409 | 410 | # Visual Studio LightSwitch build output 411 | **/*.HTMLClient/GeneratedArtifacts 412 | **/*.DesktopClient/GeneratedArtifacts 413 | **/*.DesktopClient/ModelManifest.xml 414 | **/*.Server/GeneratedArtifacts 415 | **/*.Server/ModelManifest.xml 416 | _Pvt_Extensions 417 | 418 | # Paket dependency manager 419 | .paket/paket.exe 420 | paket-files/ 421 | 422 | # FAKE - F# Make 423 | .fake/ 424 | 425 | # CodeRush personal settings 426 | .cr/personal 427 | 428 | # Python Tools for Visual Studio (PTVS) 429 | __pycache__/ 430 | *.pyc 431 | 432 | # Cake - Uncomment if you are using it 433 | # tools/** 434 | # !tools/packages.config 435 | 436 | # Tabs Studio 437 | *.tss 438 | 439 | # Telerik's JustMock configuration file 440 | *.jmconfig 441 | 442 | # BizTalk build output 443 | *.btp.cs 444 | *.btm.cs 445 | *.odx.cs 446 | *.xsd.cs 447 | 448 | # OpenCover UI analysis results 449 | OpenCover/ 450 | 451 | # Azure Stream Analytics local run output 452 | ASALocalRun/ 453 | 454 | # MSBuild Binary and Structured Log 455 | *.binlog 456 | 457 | # NVidia Nsight GPU debugger configuration file 458 | *.nvuser 459 | 460 | # MFractors (Xamarin productivity tool) working folder 461 | .mfractor/ 462 | 463 | # Local History for Visual Studio 464 | .localhistory/ 465 | 466 | # BeatPulse healthcheck temp database 467 | healthchecksdb 468 | 469 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 470 | MigrationBackup/ 471 | 472 | # Ionide (cross platform F# VS Code tools) working folder 473 | .ionide/ 474 | 475 | # Fody - auto-generated XML schema 476 | FodyWeavers.xsd 477 | 478 | # VS Code files for those working on multiple tools 479 | .vscode/* 480 | !.vscode/settings.json 481 | !.vscode/tasks.json 482 | !.vscode/launch.json 483 | !.vscode/extensions.json 484 | *.code-workspace 485 | 486 | # Local History for Visual Studio Code 487 | .history/ 488 | 489 | # Windows Installer files from build outputs 490 | 491 | # JetBrains Rider 492 | .idea/ 493 | *.sln.iml 494 | 495 | ### VisualStudio Patch ### 496 | # Additional files built by Visual Studio 497 | 498 | # End of https://www.toptal.com/developers/gitignore/api/qt,windows,c++,visualstudio -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(Qt3DViewer VERSION 0.1 LANGUAGES CXX) 4 | 5 | 6 | 7 | set(CMAKE_CXX_STANDARD 11) 8 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 9 | 10 | 11 | SET(Qt5_DIR D:/Librarys/Qt/Qt5.12.10/5.12.10/msvc2015_64/lib/cmake/Qt5) 12 | SET(OpenMesh_DIR D:/Librarys/OpenMesh8.1/share/OpenMesh/cmake) 13 | 14 | 15 | SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} Qt5_DIR OpenMesh_DIR) 16 | SET(CMAKE_INCLUDE_CURRENT_DIR ON) 17 | SEt(CMAKE_AUTOMOC ON) 18 | SEt(CMAKE_AUTORCC ON) 19 | SET(CMAKE_AUTOUIC ON) 20 | 21 | 22 | 23 | FIND_PACKAGE(Qt5 COMPONENTS Core Widgets Gui OpenGL REQUIRED) 24 | FIND_PACKAGE(OpenMesh REQUIRED) 25 | 26 | # QtCreator supports the following variables for Android, which are identical to qmake Android variables. 27 | # Check https://doc.qt.io/qt/deployment-android.html for more information. 28 | # They need to be set before the find_package( ...) calls below. 29 | 30 | #if(ANDROID) 31 | # set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") 32 | # if (ANDROID_ABI STREQUAL "armeabi-v7a") 33 | # set(ANDROID_EXTRA_LIBS 34 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so 35 | # ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so) 36 | # endif() 37 | #endif() 38 | 39 | #find_package(Qt5 COMPONENTS Widgets OpenGL REQUIRED) 40 | 41 | 42 | set(PROJECT_SOURCES 43 | main.cpp 44 | Qt3DViewer.cpp 45 | Qt3DViewer.h 46 | Qt3DViewer.ui 47 | Qt3DViewer.qrc 48 | openmeshApps/MeshViewerWidget.cpp 49 | openmeshApps/MeshViewerWidget.h 50 | openmeshApps/MeshViewerWidgetT.h 51 | openmeshApps/MeshViewerWidgetT_impl.h 52 | openmeshApps/QGLViewerWidget.h 53 | openmeshApps/QGLViewerWidget.cpp 54 | ) 55 | 56 | 57 | add_definitions(-D_USE_MATH_DEFINES) 58 | 59 | 60 | add_executable(Qt3DViewer 61 | ${PROJECT_SOURCES} 62 | ) 63 | 64 | TARGET_LINK_DIRECTORIES(${CMAKE_PROJECT_NAME} PUBLIC 65 | D:/Librarys/OpenMesh8.1/lib 66 | ) 67 | 68 | #INCLUDE_DIRECTORIES( 69 | 70 | #) 71 | target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC 72 | D:/Librarys/OpenMesh8.1/include 73 | ${CMAKE_CURRENT_SOURCE_DIR} 74 | ) 75 | 76 | target_link_libraries( Qt3DViewer 77 | Qt5::Core 78 | Qt5::Widgets 79 | Qt5::Gui 80 | Qt5::OpenGL 81 | debug OpenMeshCored 82 | debug OpenMeshToolsd 83 | optimized OpenMeshCore 84 | optimized OpenMeshTools 85 | OpenGL32.lib 86 | ) 87 | 88 | 89 | set_target_properties(Qt3DViewer PROPERTIES 90 | MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com 91 | MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} 92 | MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} 93 | ) 94 | 95 | 96 | message(STATUS {"${OpenMesh_INCLUDE_DIRS}"}) -------------------------------------------------------------------------------- /Qt3DViewer.cpp: -------------------------------------------------------------------------------- 1 | #include "Qt3DViewer.h" 2 | #include "openmeshApps/MeshViewerWidget.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | Qt3DViewer::Qt3DViewer(QWidget *parent) 9 | : QMainWindow(parent) 10 | , _meshViewerWidget(new MeshViewerWidget()) 11 | , _importMeshAction(new QAction(this)) 12 | ,_setTexture(new QAction(this)) 13 | { 14 | ui.setupUi(this); 15 | 16 | OpenMesh::IO::Options opt; 17 | // enable most options for now 18 | opt += OpenMesh::IO::Options::VertexColor; 19 | opt += OpenMesh::IO::Options::VertexNormal; 20 | opt += OpenMesh::IO::Options::VertexTexCoord; 21 | opt += OpenMesh::IO::Options::FaceColor; 22 | opt += OpenMesh::IO::Options::FaceNormal; 23 | opt += OpenMesh::IO::Options::FaceTexCoord; 24 | 25 | _meshViewerWidget->setOptions(opt); 26 | setCentralWidget(_meshViewerWidget); 27 | 28 | createActions(); 29 | createMenus(); 30 | createToolbars(); 31 | } 32 | 33 | 34 | void Qt3DViewer::displayMesh() 35 | { 36 | OpenMesh::IO::Options opt; 37 | _meshViewerWidget->open_mesh("E:/skull.stl", opt); 38 | } 39 | 40 | void Qt3DViewer::createMenus() 41 | { 42 | QMenu *fileMenu = this->menuBar()->addMenu(tr("File")); 43 | fileMenu->addAction(_importMeshAction); 44 | fileMenu->addAction(_setTexture); 45 | } 46 | 47 | void Qt3DViewer::createToolbars() 48 | { 49 | ui.mainToolBar->addAction(_importMeshAction); 50 | } 51 | 52 | void Qt3DViewer::createActions() 53 | { 54 | _importMeshAction->setIcon(QIcon(":/Qt3DViewer/Resources/images/importMesh.png")); 55 | _importMeshAction->setText(tr("Import Mesh")); 56 | connect(_importMeshAction, &QAction::triggered, this, &Qt3DViewer::importMesh); 57 | 58 | _setTexture->setText(tr("Set Texture")); 59 | connect(_setTexture, &QAction::triggered, this, &Qt3DViewer::setTexture); 60 | } 61 | 62 | void Qt3DViewer::importMesh() 63 | { 64 | _meshViewerWidget->query_open_mesh_file(); 65 | 66 | /*QString fileName = QFileDialog::getOpenFileName(this, tr("Import Mesh"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), "STL(*.stl)"); 67 | if (!fileName.isEmpty()) 68 | { 69 | OpenMesh::IO::Options opt; 70 | _meshViewerWidget->open_mesh(fileName.toLocal8Bit().data(), opt); 71 | }*/ 72 | } 73 | 74 | void Qt3DViewer::setTexture() 75 | { 76 | _meshViewerWidget->query_open_texture_file(); 77 | 78 | } -------------------------------------------------------------------------------- /Qt3DViewer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ui_Qt3DViewer.h" 5 | 6 | class MeshViewerWidget; 7 | class QAction; 8 | class QToolBar; 9 | class Qt3DViewer : public QMainWindow 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | Qt3DViewer(QWidget *parent = Q_NULLPTR); 15 | private slots: 16 | void importMesh(); 17 | void setTexture(); 18 | private: 19 | Ui::Qt3DViewerClass ui; 20 | 21 | MeshViewerWidget* _meshViewerWidget; 22 | QAction* _importMeshAction; 23 | QAction* _setTexture; 24 | QToolBar* _fileToolBar; 25 | 26 | void displayMesh(); 27 | void createMenus(); 28 | void createToolbars(); 29 | void createActions(); 30 | }; 31 | -------------------------------------------------------------------------------- /Qt3DViewer.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | Resources/images/importMesh.png 4 | 5 | 6 | -------------------------------------------------------------------------------- /Qt3DViewer.ui: -------------------------------------------------------------------------------- 1 | 2 | Qt3DViewerClass 3 | 4 | 5 | Qt3DViewerClass 6 | 7 | 8 | 9 | 0 10 | 0 11 | 600 12 | 400 13 | 14 | 15 | 16 | Qt3DViewer 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qt3DViewer 2 | openmesh + qt 3 | You can configure the specific version of OpenMesh and Qt. I use OpenMesh 8.1 that is the latest version and Qt5.15.2. This project is derived from QtViewer which exists in Apps in the directory of OpenMesh source code. I just modified some code snippets of header files and used CMake to generate the Visual Studio 2019 project. 4 | ![image](https://github.com/windless1015/Qt3DViewer/blob/master/screenshot/Q3DViewer.png) 5 | -------------------------------------------------------------------------------- /Resources/images/importMesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/windless1015/Qt3DViewer/b335dd10ad5125cae68b3e9e7004f67a2eca3a7a/Resources/images/importMesh.png -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "Qt3DViewer.h" 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "openmeshApps/MeshViewerWidget.h" 13 | 14 | void create_menu(QMainWindow& w); 15 | 16 | int main(int argc, char *argv[]) 17 | { 18 | 19 | //MyMesh mesh; 20 | //// generate vertices 21 | //MyMesh::VertexHandle vhandle[8]; 22 | //vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1)); 23 | //vhandle[1] = mesh.add_vertex(MyMesh::Point(1, -1, 1)); 24 | //vhandle[2] = mesh.add_vertex(MyMesh::Point(1, 1, 1)); 25 | //vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1)); 26 | //vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1)); 27 | //vhandle[5] = mesh.add_vertex(MyMesh::Point(1, -1, -1)); 28 | //vhandle[6] = mesh.add_vertex(MyMesh::Point(1, 1, -1)); 29 | //vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1)); 30 | //// generate (quadrilateral) faces 31 | //std::vector face_vhandles; 32 | //face_vhandles.clear(); 33 | //face_vhandles.push_back(vhandle[0]); 34 | //face_vhandles.push_back(vhandle[1]); 35 | //face_vhandles.push_back(vhandle[2]); 36 | //face_vhandles.push_back(vhandle[3]); 37 | //mesh.add_face(face_vhandles); 38 | 39 | //face_vhandles.clear(); 40 | //face_vhandles.push_back(vhandle[7]); 41 | //face_vhandles.push_back(vhandle[6]); 42 | //face_vhandles.push_back(vhandle[5]); 43 | //face_vhandles.push_back(vhandle[4]); 44 | //mesh.add_face(face_vhandles); 45 | //face_vhandles.clear(); 46 | //face_vhandles.push_back(vhandle[1]); 47 | //face_vhandles.push_back(vhandle[0]); 48 | //face_vhandles.push_back(vhandle[4]); 49 | //face_vhandles.push_back(vhandle[5]); 50 | //mesh.add_face(face_vhandles); 51 | //face_vhandles.clear(); 52 | //face_vhandles.push_back(vhandle[2]); 53 | //face_vhandles.push_back(vhandle[1]); 54 | //face_vhandles.push_back(vhandle[5]); 55 | //face_vhandles.push_back(vhandle[6]); 56 | //mesh.add_face(face_vhandles); 57 | //face_vhandles.clear(); 58 | //face_vhandles.push_back(vhandle[3]); 59 | //face_vhandles.push_back(vhandle[2]); 60 | //face_vhandles.push_back(vhandle[6]); 61 | //face_vhandles.push_back(vhandle[7]); 62 | //mesh.add_face(face_vhandles); 63 | //face_vhandles.clear(); 64 | //face_vhandles.push_back(vhandle[0]); 65 | //face_vhandles.push_back(vhandle[3]); 66 | //face_vhandles.push_back(vhandle[7]); 67 | //face_vhandles.push_back(vhandle[4]); 68 | //mesh.add_face(face_vhandles); 69 | //// write mesh to output.obj 70 | 71 | //if (!OpenMesh::IO::write_mesh(mesh, "D:/output.obj")) 72 | //{ 73 | // std::cerr << "Cannot write mesh to file 'output.off'" << std::endl; 74 | //} 75 | 76 | QApplication a(argc, argv); 77 | Qt3DViewer w; 78 | w.show(); 79 | return a.exec(); 80 | 81 | 82 | 83 | 84 | 85 | //QApplication::setColorSpec(QApplication::CustomColor); 86 | //QApplication app(argc, argv); 87 | 88 | //int c; 89 | //OpenMesh::IO::Options opt; 90 | 91 | 92 | //// enable most options for now 93 | //opt += OpenMesh::IO::Options::VertexColor; 94 | //opt += OpenMesh::IO::Options::VertexNormal; 95 | //opt += OpenMesh::IO::Options::VertexTexCoord; 96 | //opt += OpenMesh::IO::Options::FaceColor; 97 | //opt += OpenMesh::IO::Options::FaceNormal; 98 | //opt += OpenMesh::IO::Options::FaceTexCoord; 99 | 100 | //// create widget 101 | //QMainWindow mainWin; 102 | //MeshViewerWidget w(&mainWin); 103 | //w.setOptions(opt); 104 | //mainWin.setCentralWidget(&w); 105 | 106 | //create_menu(mainWin); 107 | 108 | //// static mesh, hence use strips 109 | ////w.enable_strips(); 110 | 111 | //mainWin.resize(640, 480); 112 | //mainWin.show(); 113 | 114 | //// load scene if specified on the command line 115 | //if (optind < argc) 116 | //{ 117 | // w.open_mesh_gui(argv[optind]); 118 | //} 119 | 120 | //if (++optind < argc) 121 | //{ 122 | // w.open_texture_gui(argv[optind]); 123 | //} 124 | 125 | //return app.exec(); 126 | 127 | } 128 | 129 | void create_menu(QMainWindow& w) 130 | { 131 | using namespace Qt; 132 | QMenu* fileMenu = w.menuBar()->addMenu(w.tr("&File")); 133 | 134 | QAction* openAct = new QAction(w.tr("&Open mesh..."), &w); 135 | openAct->setShortcut(w.tr("Ctrl+O")); 136 | openAct->setStatusTip(w.tr("Open a mesh file")); 137 | QObject::connect(openAct, SIGNAL(triggered()), w.centralWidget(), SLOT(query_open_mesh_file())); 138 | fileMenu->addAction(openAct); 139 | 140 | QAction* texAct = new QAction(w.tr("Open &texture..."), &w); 141 | texAct->setShortcut(w.tr("Ctrl+T")); 142 | texAct->setStatusTip(w.tr("Open a texture file")); 143 | QObject::connect(texAct, SIGNAL(triggered()), w.centralWidget(), SLOT(query_open_texture_file())); 144 | fileMenu->addAction(texAct); 145 | } 146 | -------------------------------------------------------------------------------- /openmeshApps/MeshViewerWidget.cpp: -------------------------------------------------------------------------------- 1 | /* ========================================================================= * 2 | * * 3 | * OpenMesh * 4 | * Copyright (c) 2001-2015, RWTH-Aachen University * 5 | * Department of Computer Graphics and Multimedia * 6 | * All rights reserved. * 7 | * www.openmesh.org * 8 | * * 9 | *---------------------------------------------------------------------------* 10 | * This file is part of OpenMesh. * 11 | *---------------------------------------------------------------------------* 12 | * * 13 | * Redistribution and use in source and binary forms, with or without * 14 | * modification, are permitted provided that the following conditions * 15 | * are met: * 16 | * * 17 | * 1. Redistributions of source code must retain the above copyright notice, * 18 | * this list of conditions and the following disclaimer. * 19 | * * 20 | * 2. Redistributions in binary form must reproduce the above copyright * 21 | * notice, this list of conditions and the following disclaimer in the * 22 | * documentation and/or other materials provided with the distribution. * 23 | * * 24 | * 3. Neither the name of the copyright holder nor the names of its * 25 | * contributors may be used to endorse or promote products derived from * 26 | * this software without specific prior written permission. * 27 | * * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 31 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * 32 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * 33 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * 34 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 35 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 39 | * * 40 | * ========================================================================= */ 41 | 42 | 43 | 44 | #define OPENMESHAPPS_MESHVIEWERWIDGET_CC 45 | 46 | //== INCLUDES ================================================================= 47 | 48 | //#include 49 | #include 50 | 51 | 52 | //== IMPLEMENTATION ========================================================== 53 | 54 | /// default constructor 55 | MeshViewerWidget::MeshViewerWidget(QWidget* parent) : MeshViewerWidgetT(parent) 56 | {} 57 | 58 | void MeshViewerWidget::open_mesh_gui(QString fname) 59 | { 60 | OpenMesh::Utils::Timer t; 61 | t.start(); 62 | if ( fname.isEmpty() || !open_mesh(fname.toLocal8Bit(), _options) ) 63 | { 64 | QString msg = "Cannot read mesh from file:\n '"; 65 | msg += fname; 66 | msg += "'"; 67 | QMessageBox::critical( nullptr, windowTitle(), msg); 68 | } 69 | t.stop(); 70 | std::cout << "Loaded mesh in ~" << t.as_string() << std::endl; 71 | 72 | } 73 | 74 | void MeshViewerWidget::open_texture_gui(QString fname) 75 | { 76 | if ( fname.isEmpty() || !open_texture( fname.toLocal8Bit() ) ) 77 | { 78 | QString msg = "Cannot load texture image from file:\n '"; 79 | msg += fname; 80 | msg += "'\n\nPossible reasons:\n"; 81 | msg += "- Mesh file didn't provide texture coordinates\n"; 82 | msg += "- Texture file does not exist\n"; 83 | msg += "- Texture file is not accessible.\n"; 84 | QMessageBox::warning( nullptr, windowTitle(), msg ); 85 | } 86 | } 87 | 88 | void MeshViewerWidget::query_open_mesh_file() { 89 | QString fileName = QFileDialog::getOpenFileName(this, 90 | tr("Open mesh file"), 91 | tr(""), 92 | tr("OBJ Files (*.obj);;" 93 | "OFF Files (*.off);;" 94 | "STL Files (*.stl);;" 95 | "All Files (*)")); 96 | if (!fileName.isEmpty()) 97 | open_mesh_gui(fileName); 98 | } 99 | 100 | void MeshViewerWidget::query_open_texture_file() { 101 | QString fileName = QFileDialog::getOpenFileName(this, 102 | tr("Open texture file"), 103 | tr(""), 104 | tr("PNG Files (*.png);;" 105 | "BMP Files (*.bmp);;" 106 | "GIF Files (*.gif);;" 107 | "JPEG Files (*.jpg);;" 108 | "TIFF Files (*.tif);;" 109 | "All Files (*)")); 110 | if (!fileName.isEmpty()) 111 | open_texture_gui(fileName); 112 | } 113 | 114 | //============================================================================= 115 | 116 | -------------------------------------------------------------------------------- /openmeshApps/MeshViewerWidget.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= * 2 | * * 3 | * OpenMesh * 4 | * Copyright (c) 2001-2015, RWTH-Aachen University * 5 | * Department of Computer Graphics and Multimedia * 6 | * All rights reserved. * 7 | * www.openmesh.org * 8 | * * 9 | *---------------------------------------------------------------------------* 10 | * This file is part of OpenMesh. * 11 | *---------------------------------------------------------------------------* 12 | * * 13 | * Redistribution and use in source and binary forms, with or without * 14 | * modification, are permitted provided that the following conditions * 15 | * are met: * 16 | * * 17 | * 1. Redistributions of source code must retain the above copyright notice, * 18 | * this list of conditions and the following disclaimer. * 19 | * * 20 | * 2. Redistributions in binary form must reproduce the above copyright * 21 | * notice, this list of conditions and the following disclaimer in the * 22 | * documentation and/or other materials provided with the distribution. * 23 | * * 24 | * 3. Neither the name of the copyright holder nor the names of its * 25 | * contributors may be used to endorse or promote products derived from * 26 | * this software without specific prior written permission. * 27 | * * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 31 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * 32 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * 33 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * 34 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 35 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 39 | * * 40 | * ========================================================================= */ 41 | 42 | 43 | 44 | #pragma once 45 | 46 | //== INCLUDES ================================================================= 47 | 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | 59 | //== CLASS DEFINITION ========================================================= 60 | 61 | using namespace OpenMesh; 62 | using namespace OpenMesh::Attributes; 63 | 64 | struct MeshViewerWidgetTraits : public OpenMesh::DefaultTraits 65 | { 66 | HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge); 67 | }; 68 | 69 | typedef OpenMesh::TriMesh_ArrayKernelT MyMesh; 70 | 71 | 72 | 73 | //== CLASS DEFINITION ========================================================= 74 | 75 | class MeshViewerWidget : public MeshViewerWidgetT 76 | { 77 | Q_OBJECT 78 | 79 | public: 80 | /// default constructor 81 | explicit MeshViewerWidget(QWidget* parent=0); 82 | 83 | OpenMesh::IO::Options& options() { return _options; } 84 | const OpenMesh::IO::Options& options() const { return _options; } 85 | void setOptions(const OpenMesh::IO::Options& opts) { _options = opts; } 86 | 87 | void open_mesh_gui(QString fname); 88 | 89 | void open_texture_gui(QString fname); 90 | 91 | public slots: 92 | void query_open_mesh_file(); 93 | 94 | void query_open_texture_file(); 95 | private: 96 | OpenMesh::IO::Options _options; 97 | }; 98 | 99 | -------------------------------------------------------------------------------- /openmeshApps/MeshViewerWidgetT.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= * 2 | * * 3 | * OpenMesh * 4 | * Copyright (c) 2001-2015, RWTH-Aachen University * 5 | * Department of Computer Graphics and Multimedia * 6 | * All rights reserved. * 7 | * www.openmesh.org * 8 | * * 9 | *---------------------------------------------------------------------------* 10 | * This file is part of OpenMesh. * 11 | *---------------------------------------------------------------------------* 12 | * * 13 | * Redistribution and use in source and binary forms, with or without * 14 | * modification, are permitted provided that the following conditions * 15 | * are met: * 16 | * * 17 | * 1. Redistributions of source code must retain the above copyright notice, * 18 | * this list of conditions and the following disclaimer. * 19 | * * 20 | * 2. Redistributions in binary form must reproduce the above copyright * 21 | * notice, this list of conditions and the following disclaimer in the * 22 | * documentation and/or other materials provided with the distribution. * 23 | * * 24 | * 3. Neither the name of the copyright holder nor the names of its * 25 | * contributors may be used to endorse or promote products derived from * 26 | * this software without specific prior written permission. * 27 | * * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 31 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * 32 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * 33 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * 34 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 35 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 39 | * * 40 | * ========================================================================= */ 41 | 42 | 43 | 44 | 45 | #pragma once 46 | 47 | 48 | //== INCLUDES ================================================================= 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | //#include 59 | #include 60 | 61 | 62 | //== FORWARDS ================================================================= 63 | 64 | class QImage; 65 | 66 | 67 | //== CLASS DEFINITION ========================================================= 68 | 69 | 70 | template 71 | class MeshViewerWidgetT : public QGLViewerWidget 72 | { 73 | 74 | public: 75 | 76 | typedef M Mesh; 77 | typedef OpenMesh::StripifierT MyStripifier; 78 | public: 79 | 80 | /// default constructor 81 | explicit MeshViewerWidgetT(QWidget* _parent=0) 82 | : QGLViewerWidget(_parent), 83 | f_strips_(false), 84 | tex_id_(0), 85 | tex_mode_(GL_MODULATE), 86 | strips_(mesh_), 87 | use_color_(true), 88 | show_vnormals_(false), 89 | show_fnormals_(false), 90 | normal_scale_(1.0) 91 | { 92 | add_draw_mode("Points"); 93 | add_draw_mode("Hidden-Line"); 94 | #if defined(OM_USE_OSG) && OM_USE_OSG 95 | add_draw_mode("OpenSG Indices"); 96 | #endif 97 | } 98 | 99 | /// destructor 100 | ~MeshViewerWidgetT() {} 101 | 102 | public: 103 | 104 | /// open mesh 105 | virtual bool open_mesh(const char* _filename, OpenMesh::IO::Options _opt); 106 | 107 | /// load texture 108 | virtual bool open_texture( const char *_filename ); 109 | bool set_texture( QImage& _texsrc ); 110 | 111 | void enable_strips(); 112 | void disable_strips(); 113 | 114 | 115 | Mesh& mesh() { return mesh_; } 116 | const Mesh& mesh() const { return mesh_; } 117 | 118 | protected: 119 | 120 | /// inherited drawing method 121 | virtual void draw_scene(const std::string& _draw_mode) override; 122 | 123 | protected: 124 | 125 | /// draw the mesh 126 | virtual void draw_openmesh(const std::string& _drawmode); 127 | 128 | 129 | void glVertex( const typename Mesh::VertexHandle _vh ) 130 | { glVertex3fv( &mesh_.point( _vh )[0] ); } 131 | 132 | void glVertex( const typename Mesh::Point& _p ) 133 | { glVertex3fv( &_p[0] ); } 134 | 135 | void glNormal( const typename Mesh::VertexHandle _vh ) 136 | { glNormal3fv( &mesh_.normal( _vh )[0] ); } 137 | 138 | void glTexCoord( const typename Mesh::VertexHandle _vh ) 139 | { glTexCoord2fv( &mesh_.texcoord(_vh)[0] ); } 140 | 141 | void glColor( const typename Mesh::VertexHandle _vh ) 142 | { glColor3ubv( &mesh_.color(_vh)[0] ); } 143 | 144 | // face properties 145 | 146 | void glNormal( const typename Mesh::FaceHandle _fh ) 147 | { glNormal3fv( &mesh_.normal( _fh )[0] ); } 148 | 149 | void glColor( const typename Mesh::FaceHandle _fh ) 150 | { glColor3ubv( &mesh_.color(_fh)[0] ); } 151 | 152 | void glMaterial( const typename Mesh::FaceHandle _fh, 153 | int _f=GL_FRONT_AND_BACK, int _m=GL_DIFFUSE ) 154 | { 155 | OpenMesh::Vec3f c=OpenMesh::color_cast(mesh_.color(_fh)); 156 | OpenMesh::Vec4f m( c[0], c[1], c[2], 1.0f ); 157 | 158 | glMaterialfv(_f, _m, &m[0]); 159 | } 160 | 161 | 162 | protected: // Strip support 163 | 164 | void compute_strips(void) 165 | { 166 | if (f_strips_) 167 | { 168 | strips_.clear(); 169 | strips_.stripify(); 170 | } 171 | } 172 | 173 | protected: // inherited 174 | 175 | virtual void keyPressEvent( QKeyEvent* _event) override; 176 | 177 | protected: 178 | 179 | bool f_strips_; // enable/disable strip usage 180 | GLuint tex_id_; 181 | GLint tex_mode_; 182 | OpenMesh::IO::Options opt_; // mesh file contained texcoords? 183 | 184 | Mesh mesh_; 185 | MyStripifier strips_; 186 | bool use_color_; 187 | bool show_vnormals_; 188 | bool show_fnormals_; 189 | float normal_scale_; 190 | OpenMesh::FPropHandleT< typename Mesh::Point > fp_normal_base_; 191 | }; 192 | 193 | 194 | //============================================================================= 195 | #if defined(OM_INCLUDE_TEMPLATES) 196 | # define OPENMESH_MESHVIEWERWIDGET_TEMPLATES 197 | # include "MeshViewerWidgetT_impl.h" 198 | #endif 199 | //============================================================================= 200 | 201 | -------------------------------------------------------------------------------- /openmeshApps/MeshViewerWidgetT_impl.h: -------------------------------------------------------------------------------- 1 | /* ========================================================================= * 2 | * * 3 | * OpenMesh * 4 | * Copyright (c) 2001-2015, RWTH-Aachen University * 5 | * Department of Computer Graphics and Multimedia * 6 | * All rights reserved. * 7 | * www.openmesh.org * 8 | * * 9 | *---------------------------------------------------------------------------* 10 | * This file is part of OpenMesh. * 11 | *---------------------------------------------------------------------------* 12 | * * 13 | * Redistribution and use in source and binary forms, with or without * 14 | * modification, are permitted provided that the following conditions * 15 | * are met: * 16 | * * 17 | * 1. Redistributions of source code must retain the above copyright notice, * 18 | * this list of conditions and the following disclaimer. * 19 | * * 20 | * 2. Redistributions in binary form must reproduce the above copyright * 21 | * notice, this list of conditions and the following disclaimer in the * 22 | * documentation and/or other materials provided with the distribution. * 23 | * * 24 | * 3. Neither the name of the copyright holder nor the names of its * 25 | * contributors may be used to endorse or promote products derived from * 26 | * this software without specific prior written permission. * 27 | * * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 31 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * 32 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * 33 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * 34 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 35 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 39 | * * 40 | * ========================================================================= */ 41 | 42 | #pragma once 43 | 44 | //== INCLUDES ================================================================= 45 | 46 | #ifdef _MSC_VER 47 | //# pragma warning(disable: 4267 4311) 48 | #endif 49 | 50 | // 51 | #include 52 | #include 53 | // -------------------- 54 | #include 55 | #include 56 | #include 57 | // -------------------- 58 | #include 59 | #include 60 | //#include 61 | #include 62 | 63 | using namespace OpenMesh; 64 | using namespace Qt; 65 | 66 | #if defined(_MSC_VER) 67 | # undef min 68 | # undef max 69 | #endif 70 | 71 | //== IMPLEMENTATION ========================================================== 72 | 73 | 74 | template 75 | bool 76 | MeshViewerWidgetT::open_mesh(const char* _filename, IO::Options _opt) 77 | { 78 | // load mesh 79 | // calculate normals 80 | // set scene center and radius 81 | 82 | mesh_.request_face_normals(); 83 | mesh_.request_face_colors(); 84 | mesh_.request_vertex_normals(); 85 | mesh_.request_vertex_colors(); 86 | mesh_.request_vertex_texcoords2D(); 87 | 88 | std::cout << "Loading from file '" << _filename << "'\n"; 89 | if ( IO::read_mesh(mesh_, _filename, _opt )) 90 | { 91 | // store read option 92 | opt_ = _opt; 93 | 94 | // update face and vertex normals 95 | if ( ! opt_.check( IO::Options::FaceNormal ) ) 96 | mesh_.update_face_normals(); 97 | else 98 | std::cout << "File provides face normals\n"; 99 | 100 | if ( ! opt_.check( IO::Options::VertexNormal ) ) 101 | mesh_.update_vertex_normals(); 102 | else 103 | std::cout << "File provides vertex normals\n"; 104 | 105 | 106 | // check for possible color information 107 | if ( opt_.check( IO::Options::VertexColor ) ) 108 | { 109 | std::cout << "File provides vertex colors\n"; 110 | add_draw_mode("Colored Vertices"); 111 | } 112 | else 113 | mesh_.release_vertex_colors(); 114 | 115 | if ( _opt.check( IO::Options::FaceColor ) ) 116 | { 117 | std::cout << "File provides face colors\n"; 118 | add_draw_mode("Solid Colored Faces"); 119 | add_draw_mode("Smooth Colored Faces"); 120 | } 121 | else 122 | mesh_.release_face_colors(); 123 | 124 | if ( _opt.check( IO::Options::VertexTexCoord ) ) 125 | std::cout << "File provides texture coordinates\n"; 126 | 127 | 128 | // bounding box 129 | typename Mesh::ConstVertexIter vIt(mesh_.vertices_begin()); 130 | typename Mesh::ConstVertexIter vEnd(mesh_.vertices_end()); 131 | 132 | using OpenMesh::Vec3f; 133 | 134 | Vec3f bbMin, bbMax; 135 | 136 | bbMin = bbMax = OpenMesh::vector_cast(mesh_.point(*vIt)); 137 | 138 | for (size_t count=0; vIt!=vEnd; ++vIt, ++count) 139 | { 140 | bbMin.minimize( OpenMesh::vector_cast(mesh_.point(*vIt))); 141 | bbMax.maximize( OpenMesh::vector_cast(mesh_.point(*vIt))); 142 | } 143 | 144 | 145 | // set center and radius 146 | set_scene_pos( (bbMin+bbMax)*0.5f, (bbMin-bbMax).norm()*0.5f ); 147 | 148 | // for normal display 149 | normal_scale_ = (bbMax-bbMin).min()*0.05f; 150 | 151 | // info 152 | std::clog << mesh_.n_vertices() << " vertices, " 153 | << mesh_.n_edges() << " edge, " 154 | << mesh_.n_faces() << " faces\n"; 155 | 156 | // base point for displaying face normals 157 | { 158 | OpenMesh::Utils::Timer t; 159 | t.start(); 160 | mesh_.add_property( fp_normal_base_ ); 161 | typename M::FaceIter f_it = mesh_.faces_begin(); 162 | typename M::FaceVertexIter fv_it; 163 | for (;f_it != mesh_.faces_end(); ++f_it) 164 | { 165 | typename Mesh::Point v(0,0,0); 166 | for( fv_it=mesh_.fv_iter(*f_it); fv_it.is_valid(); ++fv_it) 167 | v += OpenMesh::vector_cast(mesh_.point(*fv_it)); 168 | v *= 1.0f/3.0f; 169 | mesh_.property( fp_normal_base_, *f_it ) = v; 170 | } 171 | t.stop(); 172 | std::clog << "Computed base point for displaying face normals [" 173 | << t.as_string() << "]" << std::endl; 174 | } 175 | 176 | // 177 | { 178 | std::clog << "Computing strips.." << std::flush; 179 | OpenMesh::Utils::Timer t; 180 | t.start(); 181 | compute_strips(); 182 | t.stop(); 183 | std::clog << "done [" << strips_.n_strips() 184 | << " strips created in " << t.as_string() << "]\n"; 185 | } 186 | 187 | // 188 | #if defined(WIN32) 189 | updateGL(); 190 | #endif 191 | 192 | setWindowTitle(QFileInfo(_filename).fileName()); 193 | 194 | // loading done 195 | return true; 196 | } 197 | return false; 198 | } 199 | 200 | 201 | //----------------------------------------------------------------------------- 202 | 203 | template 204 | bool MeshViewerWidgetT::open_texture( const char *_filename ) 205 | { 206 | QImage texsrc; 207 | QString fname = _filename; 208 | 209 | if (texsrc.load( fname )) 210 | { 211 | return set_texture( texsrc ); 212 | } 213 | return false; 214 | } 215 | 216 | 217 | //----------------------------------------------------------------------------- 218 | 219 | template 220 | bool MeshViewerWidgetT::set_texture( QImage& _texsrc ) 221 | { 222 | if ( !opt_.vertex_has_texcoord() ) 223 | return false; 224 | 225 | { 226 | // adjust texture size: 2^k * 2^l 227 | int tex_w, w( _texsrc.width() ); 228 | int tex_h, h( _texsrc.height() ); 229 | 230 | for (tex_w=1; tex_w <= w; tex_w <<= 1) {}; 231 | for (tex_h=1; tex_h <= h; tex_h <<= 1) {}; 232 | tex_w >>= 1; 233 | tex_h >>= 1; 234 | _texsrc = _texsrc.scaled( tex_w, tex_h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation ); 235 | } 236 | 237 | QImage texture( QGLWidget::convertToGLFormat ( _texsrc ) ); 238 | 239 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 240 | glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); 241 | glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); 242 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 243 | glPixelStorei(GL_PACK_ROW_LENGTH, 0); 244 | glPixelStorei(GL_PACK_SKIP_ROWS, 0); 245 | glPixelStorei(GL_PACK_SKIP_PIXELS, 0); 246 | glPixelStorei(GL_PACK_ALIGNMENT, 1); 247 | 248 | if ( tex_id_ > 0 ) 249 | { 250 | glDeleteTextures(1, &tex_id_); 251 | } 252 | glGenTextures(1, &tex_id_); 253 | glBindTexture(GL_TEXTURE_2D, tex_id_); 254 | 255 | // glTexGenfv( GL_S, GL_SPHERE_MAP, 0 ); 256 | // glTexGenfv( GL_T, GL_SPHERE_MAP, 0 ); 257 | 258 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 259 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 260 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 261 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 262 | 263 | glTexImage2D(GL_TEXTURE_2D, // target 264 | 0, // level 265 | GL_RGBA, // internal format 266 | texture.width(), // width (2^n) 267 | texture.height(), // height (2^m) 268 | 0, // border 269 | GL_RGBA, // format 270 | GL_UNSIGNED_BYTE, // type 271 | texture.bits() ); // pointer to pixels 272 | 273 | std::cout << "Texture loaded\n"; 274 | return true; 275 | } 276 | 277 | 278 | //----------------------------------------------------------------------------- 279 | 280 | template 281 | void 282 | MeshViewerWidgetT::draw_openmesh(const std::string& _draw_mode) 283 | { 284 | typename Mesh::ConstFaceIter fIt(mesh_.faces_begin()), 285 | fEnd(mesh_.faces_end()); 286 | 287 | typename Mesh::ConstFaceVertexIter fvIt; 288 | 289 | #if defined(OM_USE_OSG) && OM_USE_OSG 290 | if (_draw_mode == "OpenSG Indices") // -------------------------------------- 291 | { 292 | glEnableClientState(GL_VERTEX_ARRAY); 293 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 294 | 295 | glEnableClientState(GL_NORMAL_ARRAY); 296 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 297 | 298 | if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) 299 | { 300 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 301 | glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); 302 | glEnable(GL_TEXTURE_2D); 303 | glBindTexture(GL_TEXTURE_2D, tex_id_); 304 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); 305 | } 306 | 307 | glDrawElements(GL_TRIANGLES, 308 | mesh_.osg_indices()->size(), 309 | GL_UNSIGNED_INT, 310 | &mesh_.osg_indices()->getField()[0] ); 311 | 312 | glDisableClientState(GL_VERTEX_ARRAY); 313 | glDisableClientState(GL_NORMAL_ARRAY); 314 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 315 | } 316 | else 317 | #endif 318 | 319 | if (_draw_mode == "Wireframe") // ------------------------------------------- 320 | { 321 | glBegin(GL_TRIANGLES); 322 | for (; fIt!=fEnd; ++fIt) 323 | { 324 | fvIt = mesh_.cfv_iter(*fIt); 325 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 326 | ++fvIt; 327 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 328 | ++fvIt; 329 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 330 | } 331 | glEnd(); 332 | } 333 | 334 | else if (_draw_mode == "Solid Flat") // ------------------------------------- 335 | { 336 | glBegin(GL_TRIANGLES); 337 | for (; fIt!=fEnd; ++fIt) 338 | { 339 | glNormal3fv( &mesh_.normal(*fIt)[0] ); 340 | 341 | fvIt = mesh_.cfv_iter(*fIt); 342 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 343 | ++fvIt; 344 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 345 | ++fvIt; 346 | glVertex3fv( &mesh_.point(*fvIt)[0] ); 347 | } 348 | glEnd(); 349 | 350 | } 351 | 352 | 353 | else if (_draw_mode == "Solid Smooth") // ----------------------------------- 354 | { 355 | glEnableClientState(GL_VERTEX_ARRAY); 356 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 357 | 358 | glEnableClientState(GL_NORMAL_ARRAY); 359 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 360 | 361 | if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) 362 | { 363 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 364 | glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); 365 | glEnable(GL_TEXTURE_2D); 366 | glBindTexture(GL_TEXTURE_2D, tex_id_); 367 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); 368 | } 369 | 370 | glBegin(GL_TRIANGLES); 371 | for (; fIt!=fEnd; ++fIt) 372 | { 373 | fvIt = mesh_.cfv_iter(*fIt); 374 | glArrayElement(fvIt->idx()); 375 | ++fvIt; 376 | glArrayElement(fvIt->idx()); 377 | ++fvIt; 378 | glArrayElement(fvIt->idx()); 379 | } 380 | glEnd(); 381 | 382 | glDisableClientState(GL_VERTEX_ARRAY); 383 | glDisableClientState(GL_NORMAL_ARRAY); 384 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 385 | 386 | if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) 387 | { 388 | glDisable(GL_TEXTURE_2D); 389 | } 390 | } 391 | 392 | else if (_draw_mode == "Colored Vertices") // -------------------------------- 393 | { 394 | glEnableClientState(GL_VERTEX_ARRAY); 395 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 396 | 397 | glEnableClientState(GL_NORMAL_ARRAY); 398 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 399 | 400 | if ( mesh_.has_vertex_colors() ) 401 | { 402 | glEnableClientState( GL_COLOR_ARRAY ); 403 | glColorPointer(3, GL_UNSIGNED_BYTE, 0,mesh_.vertex_colors()); 404 | } 405 | 406 | glBegin(GL_TRIANGLES); 407 | for (; fIt!=fEnd; ++fIt) 408 | { 409 | fvIt = mesh_.cfv_iter(*fIt); 410 | glArrayElement(fvIt->idx()); 411 | ++fvIt; 412 | glArrayElement(fvIt->idx()); 413 | ++fvIt; 414 | glArrayElement(fvIt->idx()); 415 | } 416 | glEnd(); 417 | 418 | glDisableClientState(GL_VERTEX_ARRAY); 419 | glDisableClientState(GL_NORMAL_ARRAY); 420 | glDisableClientState(GL_COLOR_ARRAY); 421 | } 422 | 423 | 424 | else if (_draw_mode == "Solid Colored Faces") // ----------------------------- 425 | { 426 | glEnableClientState(GL_VERTEX_ARRAY); 427 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 428 | 429 | glEnableClientState(GL_NORMAL_ARRAY); 430 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 431 | 432 | glBegin(GL_TRIANGLES); 433 | for (; fIt!=fEnd; ++fIt) 434 | { 435 | glColor( *fIt ); 436 | 437 | fvIt = mesh_.cfv_iter(*fIt); 438 | glArrayElement(fvIt->idx()); 439 | ++fvIt; 440 | glArrayElement(fvIt->idx()); 441 | ++fvIt; 442 | glArrayElement(fvIt->idx()); 443 | } 444 | glEnd(); 445 | 446 | glDisableClientState(GL_VERTEX_ARRAY); 447 | glDisableClientState(GL_NORMAL_ARRAY); 448 | } 449 | 450 | 451 | else if (_draw_mode == "Smooth Colored Faces") // --------------------------- 452 | { 453 | glEnableClientState(GL_VERTEX_ARRAY); 454 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 455 | 456 | glEnableClientState(GL_NORMAL_ARRAY); 457 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 458 | 459 | glBegin(GL_TRIANGLES); 460 | for (; fIt!=fEnd; ++fIt) 461 | { 462 | glMaterial( *fIt ); 463 | 464 | fvIt = mesh_.cfv_iter(*fIt); 465 | glArrayElement(fvIt->idx()); 466 | ++fvIt; 467 | glArrayElement(fvIt->idx()); 468 | ++fvIt; 469 | glArrayElement(fvIt->idx()); 470 | } 471 | glEnd(); 472 | 473 | glDisableClientState(GL_VERTEX_ARRAY); 474 | glDisableClientState(GL_NORMAL_ARRAY); 475 | } 476 | 477 | 478 | else if ( _draw_mode == "Strips'n VertexArrays" ) // ------------------------ 479 | { 480 | glEnableClientState(GL_VERTEX_ARRAY); 481 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 482 | 483 | glEnableClientState(GL_NORMAL_ARRAY); 484 | glNormalPointer(GL_FLOAT, 0, mesh_.vertex_normals()); 485 | 486 | if ( tex_id_ && mesh_.has_vertex_texcoords2D() ) 487 | { 488 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); 489 | glTexCoordPointer(2, GL_FLOAT, 0, mesh_.texcoords2D()); 490 | glEnable(GL_TEXTURE_2D); 491 | glBindTexture(GL_TEXTURE_2D, tex_id_); 492 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, tex_mode_); 493 | } 494 | 495 | typename MyStripifier::StripsIterator strip_it = strips_.begin(); 496 | typename MyStripifier::StripsIterator strip_last = strips_.end(); 497 | 498 | // Draw all strips 499 | for (; strip_it!=strip_last; ++strip_it) 500 | { 501 | glDrawElements(GL_TRIANGLE_STRIP, 502 | static_cast(strip_it->size()), GL_UNSIGNED_INT, &(*strip_it)[0] ); 503 | } 504 | 505 | glDisableClientState(GL_VERTEX_ARRAY); 506 | glDisableClientState(GL_NORMAL_ARRAY); 507 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); 508 | } 509 | 510 | 511 | else if (_draw_mode == "Show Strips" && strips_.is_valid() ) // ------------- 512 | { 513 | typename MyStripifier::StripsIterator strip_it = strips_.begin(); 514 | typename MyStripifier::StripsIterator strip_last = strips_.end(); 515 | 516 | float cmax = 256.0f; 517 | int range = 220; 518 | int base = (int)cmax-range; 519 | int drcol = 13; 520 | int dgcol = 31; 521 | int dbcol = 17; 522 | 523 | int rcol=0, gcol=dgcol, bcol=dbcol+dbcol; 524 | 525 | // Draw all strips 526 | for (; strip_it!=strip_last; ++strip_it) 527 | { 528 | typename MyStripifier::IndexIterator idx_it = strip_it->begin(); 529 | typename MyStripifier::IndexIterator idx_last = strip_it->end(); 530 | 531 | rcol = (rcol+drcol) % range; 532 | gcol = (gcol+dgcol) % range; 533 | bcol = (bcol+dbcol) % range; 534 | 535 | glBegin(GL_TRIANGLE_STRIP); 536 | glColor3f((rcol+base)/cmax, (gcol+base)/cmax, (bcol+base)/cmax); 537 | for ( ;idx_it != idx_last; ++idx_it ) 538 | glVertex3fv(&mesh_.point( OM_TYPENAME Mesh::VertexHandle(*idx_it))[0]); 539 | glEnd(); 540 | } 541 | glColor3f(1.0, 1.0, 1.0); 542 | } 543 | 544 | 545 | else if( _draw_mode == "Points" ) // ----------------------------------------- 546 | { 547 | glEnableClientState(GL_VERTEX_ARRAY); 548 | glVertexPointer(3, GL_FLOAT, 0, mesh_.points()); 549 | 550 | if (mesh_.has_vertex_colors() && use_color_) 551 | { 552 | glEnableClientState(GL_COLOR_ARRAY); 553 | glColorPointer(3, GL_UNSIGNED_BYTE, 0, mesh_.vertex_colors()); 554 | } 555 | 556 | glDrawArrays( GL_POINTS, 0, static_cast(mesh_.n_vertices()) ); 557 | glDisableClientState(GL_VERTEX_ARRAY); 558 | glDisableClientState(GL_COLOR_ARRAY); 559 | } 560 | 561 | 562 | } 563 | 564 | 565 | //----------------------------------------------------------------------------- 566 | 567 | 568 | template 569 | void 570 | MeshViewerWidgetT::draw_scene(const std::string& _draw_mode) 571 | { 572 | 573 | if ( ! mesh_.n_vertices() ) 574 | return; 575 | 576 | #if defined(OM_USE_OSG) && OM_USE_OSG 577 | else if ( _draw_mode == "OpenSG Indices") 578 | { 579 | glEnable(GL_LIGHTING); 580 | glShadeModel(GL_SMOOTH); 581 | draw_openmesh( _draw_mode ); 582 | } 583 | else 584 | #endif 585 | if ( _draw_mode == "Points" ) 586 | { 587 | glDisable(GL_LIGHTING); 588 | draw_openmesh(_draw_mode); 589 | } 590 | else if (_draw_mode == "Wireframe") 591 | { 592 | glDisable(GL_LIGHTING); 593 | glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 594 | draw_openmesh(_draw_mode); 595 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 596 | } 597 | 598 | else if ( _draw_mode == "Hidden-Line" ) 599 | { 600 | glDisable(GL_LIGHTING); 601 | glShadeModel(GL_FLAT); 602 | glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 603 | glColor4f( 0.0f, 0.0f, 0.0f, 1.0f ); 604 | glDepthRange(0.01, 1.0); 605 | draw_openmesh( "Wireframe" ); 606 | 607 | glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); 608 | glColor4f( 1.0f, 1.0f, 1.0f, 1.0f ); 609 | glDepthRange( 0.0, 1.0 ); 610 | draw_openmesh( "Wireframe" ); 611 | 612 | glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); 613 | } 614 | 615 | else if (_draw_mode == "Solid Flat") 616 | { 617 | glEnable(GL_LIGHTING); 618 | glShadeModel(GL_FLAT); 619 | draw_openmesh(_draw_mode); 620 | } 621 | 622 | else if (_draw_mode == "Solid Smooth" || 623 | _draw_mode == "Strips'n VertexArrays" ) 624 | { 625 | glEnable(GL_LIGHTING); 626 | glShadeModel(GL_SMOOTH); 627 | draw_openmesh(_draw_mode); 628 | } 629 | 630 | else if (_draw_mode == "Show Strips") 631 | { 632 | glDisable(GL_LIGHTING); 633 | draw_openmesh(_draw_mode); 634 | } 635 | 636 | else if (_draw_mode == "Colored Vertices" ) 637 | { 638 | glDisable(GL_LIGHTING); 639 | glShadeModel(GL_SMOOTH); 640 | draw_openmesh(_draw_mode); 641 | } 642 | 643 | else if (_draw_mode == "Solid Colored Faces") 644 | { 645 | glDisable(GL_LIGHTING); 646 | glShadeModel(GL_FLAT); 647 | draw_openmesh(_draw_mode); 648 | setDefaultMaterial(); 649 | } 650 | 651 | else if (_draw_mode == "Smooth Colored Faces" ) 652 | { 653 | glEnable(GL_LIGHTING); 654 | glShadeModel(GL_SMOOTH); 655 | draw_openmesh(_draw_mode); 656 | setDefaultMaterial(); 657 | } 658 | 659 | if (show_vnormals_) 660 | { 661 | typename Mesh::VertexIter vit; 662 | glDisable(GL_LIGHTING); 663 | glBegin(GL_LINES); 664 | glColor3f(1.000f, 0.803f, 0.027f); // orange 665 | for(vit=mesh_.vertices_begin(); vit!=mesh_.vertices_end(); ++vit) 666 | { 667 | glVertex( *vit ); 668 | glVertex( mesh_.point( *vit ) + normal_scale_*mesh_.normal( *vit ) ); 669 | } 670 | glEnd(); 671 | } 672 | 673 | if (show_fnormals_) 674 | { 675 | typename Mesh::FaceIter fit; 676 | glDisable(GL_LIGHTING); 677 | glBegin(GL_LINES); 678 | glColor3f(0.705f, 0.976f, 0.270f); // greenish 679 | for(fit=mesh_.faces_begin(); fit!=mesh_.faces_end(); ++fit) 680 | { 681 | glVertex( mesh_.property(fp_normal_base_, *fit) ); 682 | glVertex( mesh_.property(fp_normal_base_, *fit) + 683 | normal_scale_*mesh_.normal( *fit ) ); 684 | } 685 | glEnd(); 686 | } 687 | } 688 | 689 | 690 | //----------------------------------------------------------------------------- 691 | 692 | template 693 | void 694 | MeshViewerWidgetT::enable_strips() 695 | { 696 | if (!f_strips_) 697 | { 698 | f_strips_ = true; 699 | add_draw_mode("Strips'n VertexArrays"); 700 | add_draw_mode("Show Strips"); 701 | } 702 | } 703 | 704 | //----------------------------------------------------------------------------- 705 | 706 | template 707 | void 708 | MeshViewerWidgetT::disable_strips() 709 | { 710 | if (f_strips_) 711 | { 712 | f_strips_ = false; 713 | del_draw_mode("Show Strips"); 714 | del_draw_mode("Strip'n VertexArrays"); 715 | } 716 | } 717 | 718 | 719 | //----------------------------------------------------------------------------- 720 | 721 | #define TEXMODE( Mode ) \ 722 | tex_mode_ = Mode; std::cout << "Texture mode set to " << #Mode << std::endl 723 | 724 | template 725 | void 726 | MeshViewerWidgetT::keyPressEvent( QKeyEvent* _event) 727 | { 728 | switch( _event->key() ) 729 | { 730 | case Key_D: 731 | if ( mesh_.has_vertex_colors() && (current_draw_mode()=="Points") ) 732 | { 733 | use_color_ = !use_color_; 734 | std::cout << "use color: " << (use_color_?"yes\n":"no\n"); 735 | if (!use_color_) 736 | glColor3f(1.0f, 1.0f, 1.0f); 737 | updateGL(); 738 | } 739 | break; 740 | 741 | case Key_N: 742 | if ( _event->modifiers() & ShiftModifier ) 743 | { 744 | show_fnormals_ = !show_fnormals_; 745 | std::cout << "show face normals: " << (show_fnormals_?"yes\n":"no\n"); 746 | } 747 | else 748 | { 749 | show_vnormals_ = !show_vnormals_; 750 | std::cout << "show vertex normals: " << (show_vnormals_?"yes\n":"no\n"); 751 | } 752 | updateGL(); 753 | break; 754 | 755 | case Key_I: 756 | std::cout << "\n# Vertices : " << mesh_.n_vertices() << std::endl; 757 | std::cout << "# Edges : " << mesh_.n_edges() << std::endl; 758 | std::cout << "# Faces : " << mesh_.n_faces() << std::endl; 759 | std::cout << "binary input : " << opt_.check(opt_.Binary) << std::endl; 760 | std::cout << "swapped input : " << opt_.check(opt_.Swap) << std::endl; 761 | std::cout << "vertex normal : " 762 | << opt_.check(opt_.VertexNormal) << std::endl; 763 | std::cout << "vertex texcoord: " 764 | << opt_.check(opt_.VertexTexCoord) << std::endl; 765 | std::cout << "vertex color : " 766 | << opt_.check(opt_.VertexColor) << std::endl; 767 | std::cout << "face normal : " 768 | << opt_.check(opt_.FaceNormal) << std::endl; 769 | std::cout << "face color : " 770 | << opt_.check(opt_.FaceColor) << std::endl; 771 | this->QGLViewerWidget::keyPressEvent( _event ); 772 | break; 773 | 774 | case Key_T: 775 | switch( tex_mode_ ) 776 | { 777 | case GL_MODULATE: TEXMODE(GL_DECAL); break; 778 | case GL_DECAL: TEXMODE(GL_BLEND); break; 779 | case GL_BLEND: TEXMODE(GL_REPLACE); break; 780 | case GL_REPLACE: TEXMODE(GL_MODULATE); break; 781 | } 782 | updateGL(); 783 | break; 784 | 785 | default: 786 | this->QGLViewerWidget::keyPressEvent( _event ); 787 | } 788 | } 789 | 790 | #undef TEXMODE 791 | 792 | //============================================================================= 793 | 794 | -------------------------------------------------------------------------------- /openmeshApps/QGLViewerWidget.cpp: -------------------------------------------------------------------------------- 1 | /* ========================================================================= * 2 | * * 3 | * OpenMesh * 4 | * Copyright (c) 2001-2015, RWTH-Aachen University * 5 | * Department of Computer Graphics and Multimedia * 6 | * All rights reserved. * 7 | * www.openmesh.org * 8 | * * 9 | *---------------------------------------------------------------------------* 10 | * This file is part of OpenMesh. * 11 | *---------------------------------------------------------------------------* 12 | * * 13 | * Redistribution and use in source and binary forms, with or without * 14 | * modification, are permitted provided that the following conditions * 15 | * are met: * 16 | * * 17 | * 1. Redistributions of source code must retain the above copyright notice, * 18 | * this list of conditions and the following disclaimer. * 19 | * * 20 | * 2. Redistributions in binary form must reproduce the above copyright * 21 | * notice, this list of conditions and the following disclaimer in the * 22 | * documentation and/or other materials provided with the distribution. * 23 | * * 24 | * 3. Neither the name of the copyright holder nor the names of its * 25 | * contributors may be used to endorse or promote products derived from * 26 | * this software without specific prior written permission. * 27 | * * 28 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * 29 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * 30 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * 31 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * 32 | * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * 33 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * 34 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * 35 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 39 | * * 40 | * ========================================================================= */ 41 | 42 | 43 | 44 | //== INCLUDES ================================================================= 45 | 46 | #ifdef _MSC_VER 47 | # pragma warning(disable: 4267 4311 4305) 48 | #endif 49 | 50 | #include 51 | #include 52 | #include 53 | #include 54 | // -------------------- 55 | 56 | // -------------------- 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | // -------------------- 64 | //#include 65 | #include 66 | #include 67 | 68 | 69 | #if !defined(M_PI) 70 | # define M_PI 3.1415926535897932 71 | #endif 72 | 73 | const double TRACKBALL_RADIUS = 0.6; 74 | 75 | 76 | using namespace Qt; 77 | using namespace OpenMesh; 78 | 79 | 80 | //== IMPLEMENTATION ========================================================== 81 | 82 | std::string QGLViewerWidget::nomode_ = ""; 83 | 84 | //---------------------------------------------------------------------------- 85 | 86 | QGLViewerWidget::QGLViewerWidget( QWidget* _parent ) 87 | : QGLWidget( _parent ) 88 | { 89 | init(); 90 | } 91 | 92 | //---------------------------------------------------------------------------- 93 | 94 | QGLViewerWidget:: 95 | QGLViewerWidget( QGLFormat& _fmt, QWidget* _parent ) 96 | : QGLWidget( _fmt, _parent ) 97 | { 98 | init(); 99 | } 100 | 101 | 102 | //---------------------------------------------------------------------------- 103 | 104 | void 105 | QGLViewerWidget::init(void) 106 | { 107 | // qt stuff 108 | setAttribute(Qt::WA_NoSystemBackground, true); 109 | setFocusPolicy(Qt::StrongFocus); 110 | setAcceptDrops( true ); 111 | setCursor(PointingHandCursor); 112 | 113 | 114 | // popup menu 115 | 116 | popup_menu_ = new QMenu(this); 117 | draw_modes_group_ = new QActionGroup(this); 118 | 119 | connect( draw_modes_group_, SIGNAL(triggered(QAction*)), 120 | this, SLOT(slotDrawMode(QAction*))); 121 | 122 | 123 | // init draw modes 124 | n_draw_modes_ = 0; 125 | //draw_mode_ = 3; 126 | QAction *a; 127 | a = add_draw_mode("Wireframe"); 128 | a->setShortcut(QKeySequence(Key_W)); 129 | add_draw_mode("Solid Flat"); 130 | a = add_draw_mode("Solid Smooth"); 131 | a->setShortcut(QKeySequence(Key_S)); 132 | a->setChecked(true); 133 | 134 | slotDrawMode(a); 135 | } 136 | 137 | 138 | //---------------------------------------------------------------------------- 139 | 140 | QGLViewerWidget::~QGLViewerWidget() 141 | { 142 | } 143 | 144 | 145 | //---------------------------------------------------------------------------- 146 | 147 | void QGLViewerWidget::setDefaultMaterial(void) 148 | { 149 | GLfloat mat_a[] = {0.1f, 0.1f, 0.1f, 1.0f}; 150 | GLfloat mat_d[] = {0.7f, 0.7f, 0.5f, 1.0f}; 151 | GLfloat mat_s[] = {1.0f, 1.0f, 1.0f, 1.0f}; 152 | GLfloat shine[] = {120.0f}; 153 | 154 | glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_a); 155 | glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_d); 156 | glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_s); 157 | glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shine); 158 | } 159 | 160 | 161 | //---------------------------------------------------------------------------- 162 | 163 | void QGLViewerWidget::setDefaultLight(void) 164 | { 165 | GLfloat pos1[] = { 0.1f, 0.1f, -0.02f, 0.0f}; 166 | GLfloat pos2[] = {-0.1f, 0.1f, -0.02f, 0.0f}; 167 | GLfloat pos3[] = { 0.0f, 0.0f, 0.1f, 0.0f}; 168 | GLfloat col1[] = { 0.7f, 0.7f, 0.8f, 1.0f}; 169 | GLfloat col2[] = { 0.8f, 0.7f, 0.7f, 1.0f}; 170 | GLfloat col3[] = { 1.0f, 1.0f, 1.0f, 1.0f}; 171 | 172 | glEnable(GL_LIGHT0); 173 | glLightfv(GL_LIGHT0,GL_POSITION, pos1); 174 | glLightfv(GL_LIGHT0,GL_DIFFUSE, col1); 175 | glLightfv(GL_LIGHT0,GL_SPECULAR, col1); 176 | 177 | glEnable(GL_LIGHT1); 178 | glLightfv(GL_LIGHT1,GL_POSITION, pos2); 179 | glLightfv(GL_LIGHT1,GL_DIFFUSE, col2); 180 | glLightfv(GL_LIGHT1,GL_SPECULAR, col2); 181 | 182 | glEnable(GL_LIGHT2); 183 | glLightfv(GL_LIGHT2,GL_POSITION, pos3); 184 | glLightfv(GL_LIGHT2,GL_DIFFUSE, col3); 185 | glLightfv(GL_LIGHT2,GL_SPECULAR, col3); 186 | } 187 | 188 | 189 | //---------------------------------------------------------------------------- 190 | 191 | 192 | void QGLViewerWidget::initializeGL() 193 | { 194 | // OpenGL state 195 | glClearColor(0.0, 0.0, 0.0, 0.0); 196 | glDisable( GL_DITHER ); 197 | glEnable( GL_DEPTH_TEST ); 198 | 199 | // Material 200 | setDefaultMaterial(); 201 | 202 | // Lighting 203 | glLoadIdentity(); 204 | setDefaultLight(); 205 | 206 | // Fog 207 | GLfloat fogColor[4] = { 0.3f, 0.3f, 0.4f, 1.0f }; 208 | glFogi(GL_FOG_MODE, GL_LINEAR); 209 | glFogfv(GL_FOG_COLOR, fogColor); 210 | glFogf(GL_FOG_DENSITY, 0.35f); 211 | glHint(GL_FOG_HINT, GL_DONT_CARE); 212 | glFogf(GL_FOG_START, 5.0f); 213 | glFogf(GL_FOG_END, 25.0f); 214 | 215 | // scene pos and size 216 | glMatrixMode(GL_MODELVIEW); 217 | glLoadIdentity(); 218 | glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); 219 | set_scene_pos(Vec3f(0.0, 0.0, 0.0), 1.0); 220 | } 221 | 222 | 223 | //---------------------------------------------------------------------------- 224 | 225 | 226 | void QGLViewerWidget::resizeGL( int _w, int _h ) 227 | { 228 | update_projection_matrix(); 229 | glViewport(0, 0, _w, _h); 230 | updateGL(); 231 | } 232 | 233 | 234 | //---------------------------------------------------------------------------- 235 | 236 | 237 | void QGLViewerWidget::paintGL() 238 | { 239 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 240 | glMatrixMode( GL_PROJECTION ); 241 | glLoadMatrixd( projection_matrix_ ); 242 | glMatrixMode( GL_MODELVIEW ); 243 | glLoadMatrixd( modelview_matrix_ ); 244 | 245 | if (draw_mode_) 246 | { 247 | assert(draw_mode_ <= n_draw_modes_); 248 | draw_scene(draw_mode_names_[draw_mode_-1]); 249 | } 250 | } 251 | 252 | 253 | //---------------------------------------------------------------------------- 254 | 255 | 256 | void QGLViewerWidget::draw_scene(const std::string& _draw_mode) 257 | { 258 | if (_draw_mode == "Wireframe") 259 | { 260 | glDisable(GL_LIGHTING); 261 | // glutWireTeapot(0.5); 262 | } 263 | 264 | else if (_draw_mode == "Solid Flat") 265 | { 266 | glEnable(GL_LIGHTING); 267 | glShadeModel(GL_FLAT); 268 | //glutSolidTeapot(0.5); 269 | } 270 | 271 | else if (_draw_mode == "Solid Smooth") 272 | { 273 | glEnable(GL_LIGHTING); 274 | glShadeModel(GL_SMOOTH); 275 | //glutSolidTeapot(0.5); 276 | } 277 | } 278 | 279 | 280 | //---------------------------------------------------------------------------- 281 | 282 | 283 | void QGLViewerWidget::mousePressEvent( QMouseEvent* _event ) 284 | { 285 | // popup menu 286 | if (_event->button() == RightButton && _event->buttons()== RightButton ) 287 | { 288 | popup_menu_->exec(QCursor::pos()); 289 | } 290 | 291 | else 292 | { 293 | last_point_ok_ = map_to_sphere( last_point_2D_=_event->pos(), 294 | last_point_3D_ ); 295 | } 296 | } 297 | 298 | 299 | //---------------------------------------------------------------------------- 300 | 301 | 302 | void QGLViewerWidget::mouseMoveEvent( QMouseEvent* _event ) 303 | { 304 | QPoint newPoint2D = _event->pos(); 305 | 306 | // Left button: rotate around center_ 307 | // Middle button: translate object 308 | // Left & middle button: zoom in/out 309 | 310 | 311 | Vec3f newPoint3D; 312 | bool newPoint_hitSphere = map_to_sphere( newPoint2D, newPoint3D ); 313 | 314 | float dx = newPoint2D.x() - last_point_2D_.x(); 315 | float dy = newPoint2D.y() - last_point_2D_.y(); 316 | 317 | float w = width(); 318 | float h = height(); 319 | 320 | 321 | 322 | // enable GL context 323 | makeCurrent(); 324 | 325 | 326 | // move in z direction 327 | if ( (_event->buttons() == (LeftButton+MidButton)) || 328 | (_event->buttons() == LeftButton && _event->modifiers() == ControlModifier)) 329 | { 330 | float value_y = radius_ * dy * 3.0 / h; 331 | translate(Vec3f(0.0, 0.0, value_y)); 332 | } 333 | 334 | 335 | // move in x,y direction 336 | else if ( (_event->buttons() == MidButton) || 337 | (_event->buttons() == LeftButton && _event->modifiers() == AltModifier) ) 338 | { 339 | float z = - (modelview_matrix_[ 2]*center_[0] + 340 | modelview_matrix_[ 6]*center_[1] + 341 | modelview_matrix_[10]*center_[2] + 342 | modelview_matrix_[14]) / 343 | (modelview_matrix_[ 3]*center_[0] + 344 | modelview_matrix_[ 7]*center_[1] + 345 | modelview_matrix_[11]*center_[2] + 346 | modelview_matrix_[15]); 347 | 348 | float aspect = w / h; 349 | float near_plane = 0.01 * radius_; 350 | float top = tan(fovy()/2.0f*M_PI/180.0f) * near_plane; 351 | float right = aspect*top; 352 | 353 | translate(Vec3f( 2.0*dx/w*right/near_plane*z, 354 | -2.0*dy/h*top/near_plane*z, 355 | 0.0f)); 356 | } 357 | 358 | 359 | 360 | // rotate 361 | else if (_event->buttons() == LeftButton) { 362 | 363 | if (last_point_ok_) { 364 | if ((newPoint_hitSphere = map_to_sphere(newPoint2D, newPoint3D))) { 365 | Vec3f axis = last_point_3D_ % newPoint3D; 366 | if (axis.sqrnorm() < 1e-7) { 367 | axis = Vec3f(1, 0, 0); 368 | } else { 369 | axis.normalize(); 370 | } 371 | // find the amount of rotation 372 | Vec3f d = last_point_3D_ - newPoint3D; 373 | float t = 0.5 * d.norm() / TRACKBALL_RADIUS; 374 | if (t < -1.0) 375 | t = -1.0; 376 | else if (t > 1.0) 377 | t = 1.0; 378 | float phi = 2.0 * asin(t); 379 | float angle = phi * 180.0 / M_PI; 380 | rotate(axis, angle); 381 | } 382 | } 383 | 384 | } 385 | 386 | 387 | // remember this point 388 | last_point_2D_ = newPoint2D; 389 | last_point_3D_ = newPoint3D; 390 | last_point_ok_ = newPoint_hitSphere; 391 | 392 | // trigger redraw 393 | updateGL(); 394 | } 395 | 396 | 397 | //---------------------------------------------------------------------------- 398 | 399 | 400 | void QGLViewerWidget::mouseReleaseEvent( QMouseEvent* /* _event */ ) 401 | { 402 | last_point_ok_ = false; 403 | } 404 | 405 | 406 | //----------------------------------------------------------------------------- 407 | 408 | 409 | void QGLViewerWidget::wheelEvent(QWheelEvent* _event) 410 | { 411 | // Use the mouse wheel to zoom in/out 412 | 413 | float d = -(float)_event->delta() / 120.0 * 0.2 * radius_; 414 | translate(Vec3f(0.0, 0.0, d)); 415 | updateGL(); 416 | _event->accept(); 417 | } 418 | 419 | 420 | //---------------------------------------------------------------------------- 421 | 422 | 423 | void QGLViewerWidget::keyPressEvent( QKeyEvent* _event) 424 | { 425 | switch( _event->key() ) 426 | { 427 | case Key_Print: 428 | slotSnapshot(); 429 | break; 430 | 431 | case Key_H: 432 | std::cout << "Keys:\n"; 433 | std::cout << " Print\tMake snapshot\n"; 434 | std::cout << " C\tenable/disable back face culling\n"; 435 | std::cout << " F\tenable/disable fog\n"; 436 | std::cout << " I\tDisplay information\n"; 437 | std::cout << " N\tenable/disable display of vertex normals\n"; 438 | std::cout << " Shift N\tenable/disable display of face normals\n"; 439 | std::cout << " Shift P\tperformance check\n"; 440 | break; 441 | 442 | case Key_C: 443 | if ( glIsEnabled( GL_CULL_FACE ) ) 444 | { 445 | glDisable( GL_CULL_FACE ); 446 | std::cout << "Back face culling: disabled\n"; 447 | } 448 | else 449 | { 450 | glEnable( GL_CULL_FACE ); 451 | std::cout << "Back face culling: enabled\n"; 452 | } 453 | updateGL(); 454 | break; 455 | 456 | case Key_F: 457 | if ( glIsEnabled( GL_FOG ) ) 458 | { 459 | glDisable( GL_FOG ); 460 | std::cout << "Fog: disabled\n"; 461 | } 462 | else 463 | { 464 | glEnable( GL_FOG ); 465 | std::cout << "Fog: enabled\n"; 466 | } 467 | updateGL(); 468 | break; 469 | 470 | case Key_I: 471 | std::cout << "Scene radius: " << radius_ << std::endl; 472 | std::cout << "Scene center: " << center_ << std::endl; 473 | break; 474 | 475 | case Key_P: 476 | if (_event->modifiers() & ShiftModifier) 477 | { 478 | double fps = performance(); 479 | std::cout << "fps: " 480 | << std::setiosflags (std::ios_base::fixed) 481 | << fps << std::endl; 482 | } 483 | break; 484 | 485 | case Key_Q: 486 | case Key_Escape: 487 | qApp->quit(); 488 | } 489 | _event->ignore(); 490 | } 491 | 492 | 493 | //---------------------------------------------------------------------------- 494 | 495 | 496 | void QGLViewerWidget::translate( const OpenMesh::Vec3f& _trans ) 497 | { 498 | // Translate the object by _trans 499 | // Update modelview_matrix_ 500 | makeCurrent(); 501 | glLoadIdentity(); 502 | glTranslated( _trans[0], _trans[1], _trans[2] ); 503 | glMultMatrixd( modelview_matrix_ ); 504 | glGetDoublev( GL_MODELVIEW_MATRIX, modelview_matrix_); 505 | } 506 | 507 | 508 | //---------------------------------------------------------------------------- 509 | 510 | 511 | void QGLViewerWidget::rotate( const OpenMesh::Vec3f& _axis, float _angle ) 512 | { 513 | // Rotate around center center_, axis _axis, by angle _angle 514 | // Update modelview_matrix_ 515 | 516 | Vec3f t( modelview_matrix_[0]*center_[0] + 517 | modelview_matrix_[4]*center_[1] + 518 | modelview_matrix_[8]*center_[2] + 519 | modelview_matrix_[12], 520 | modelview_matrix_[1]*center_[0] + 521 | modelview_matrix_[5]*center_[1] + 522 | modelview_matrix_[9]*center_[2] + 523 | modelview_matrix_[13], 524 | modelview_matrix_[2]*center_[0] + 525 | modelview_matrix_[6]*center_[1] + 526 | modelview_matrix_[10]*center_[2] + 527 | modelview_matrix_[14] ); 528 | 529 | makeCurrent(); 530 | glLoadIdentity(); 531 | glTranslatef(t[0], t[1], t[2]); 532 | glRotated( _angle, _axis[0], _axis[1], _axis[2]); 533 | glTranslatef(-t[0], -t[1], -t[2]); 534 | glMultMatrixd(modelview_matrix_); 535 | glGetDoublev(GL_MODELVIEW_MATRIX, modelview_matrix_); 536 | } 537 | 538 | 539 | //---------------------------------------------------------------------------- 540 | 541 | 542 | bool QGLViewerWidget::map_to_sphere( const QPoint& _v2D, OpenMesh::Vec3f& _v3D ) 543 | { 544 | // This is actually doing the Sphere/Hyperbolic sheet hybrid thing, 545 | // based on Ken Shoemake's ArcBall in Graphics Gems IV, 1993. 546 | double x = (2.0*_v2D.x() - width())/width(); 547 | double y = -(2.0*_v2D.y() - height())/height(); 548 | double xval = x; 549 | double yval = y; 550 | double x2y2 = xval*xval + yval*yval; 551 | 552 | const double rsqr = TRACKBALL_RADIUS*TRACKBALL_RADIUS; 553 | _v3D[0] = xval; 554 | _v3D[1] = yval; 555 | if (x2y2 < 0.5*rsqr) { 556 | _v3D[2] = sqrt(rsqr - x2y2); 557 | } else { 558 | _v3D[2] = 0.5*rsqr/sqrt(x2y2); 559 | } 560 | 561 | return true; 562 | } 563 | 564 | 565 | //---------------------------------------------------------------------------- 566 | 567 | 568 | void QGLViewerWidget::update_projection_matrix() 569 | { 570 | makeCurrent(); 571 | glMatrixMode( GL_PROJECTION ); 572 | glLoadIdentity(); 573 | 574 | const double fovY = 45.0; 575 | const double aspect = static_cast(width()) / static_cast(height()); 576 | const double zNear = 0.01*radius_; 577 | const double zFar = 100.0*radius_; 578 | 579 | // Replacement for: gluPerspective(45.0, (GLfloat) width() / (GLfloat) height(), 0.01*radius_, 100.0*radius_); 580 | const double pi = 3.1415926535897932384626433832795; 581 | const double fH = tan( fovY / 360 * pi ) * zNear; 582 | const double fW = fH * aspect; 583 | glFrustum( -fW, fW, -fH, fH, zNear, zFar ); 584 | 585 | 586 | glGetDoublev( GL_PROJECTION_MATRIX, projection_matrix_); 587 | glMatrixMode( GL_MODELVIEW ); 588 | } 589 | 590 | 591 | //---------------------------------------------------------------------------- 592 | 593 | 594 | void QGLViewerWidget::view_all() 595 | { 596 | translate( Vec3f( -(modelview_matrix_[0]*center_[0] + 597 | modelview_matrix_[4]*center_[1] + 598 | modelview_matrix_[8]*center_[2] + 599 | modelview_matrix_[12]), 600 | -(modelview_matrix_[1]*center_[0] + 601 | modelview_matrix_[5]*center_[1] + 602 | modelview_matrix_[9]*center_[2] + 603 | modelview_matrix_[13]), 604 | -(modelview_matrix_[2]*center_[0] + 605 | modelview_matrix_[6]*center_[1] + 606 | modelview_matrix_[10]*center_[2] + 607 | modelview_matrix_[14] + 608 | 3.0*radius_) ) ); 609 | } 610 | 611 | 612 | //---------------------------------------------------------------------------- 613 | 614 | 615 | void QGLViewerWidget::set_scene_pos( const OpenMesh::Vec3f& _cog, float _radius ) 616 | { 617 | center_ = _cog; 618 | radius_ = _radius; 619 | glFogf( GL_FOG_START, 1.5*_radius ); 620 | glFogf( GL_FOG_END, 3.0*_radius ); 621 | 622 | update_projection_matrix(); 623 | view_all(); 624 | } 625 | 626 | 627 | //---------------------------------------------------------------------------- 628 | 629 | 630 | QAction* QGLViewerWidget::add_draw_mode(const std::string& _s) 631 | { 632 | ++n_draw_modes_; 633 | draw_mode_names_.push_back(_s); 634 | 635 | QActionGroup *grp = draw_modes_group_; 636 | QAction* act = new QAction(tr(_s.c_str()), this); 637 | act->setCheckable(true); 638 | act->setData(n_draw_modes_); 639 | 640 | grp->addAction(act); 641 | popup_menu_->addAction(act); 642 | addAction(act, _s.c_str()); 643 | 644 | return act; 645 | } 646 | 647 | void QGLViewerWidget::addAction(QAction* act, const char * name) 648 | { 649 | names_to_actions[name] = act; 650 | Super::addAction(act); 651 | } 652 | void QGLViewerWidget::removeAction(QAction* act) 653 | { 654 | ActionMap::iterator it = names_to_actions.begin(), e = names_to_actions.end(); 655 | ActionMap::iterator found = e; 656 | for(; it!=e; ++it) { 657 | if (it->second == act) { 658 | found = it; 659 | break; 660 | } 661 | } 662 | if (found != e) { 663 | names_to_actions.erase(found); 664 | } 665 | popup_menu_->removeAction(act); 666 | draw_modes_group_->removeAction(act); 667 | Super::removeAction(act); 668 | } 669 | 670 | void QGLViewerWidget::removeAction(const char* name) 671 | { 672 | QString namestr = QString(name); 673 | ActionMap::iterator e = names_to_actions.end(); 674 | 675 | ActionMap::iterator found = names_to_actions.find(namestr); 676 | if (found != e) { 677 | removeAction(found->second); 678 | } 679 | } 680 | 681 | QAction* QGLViewerWidget::findAction(const char* name) 682 | { 683 | QString namestr = QString(name); 684 | ActionMap::iterator e = names_to_actions.end(); 685 | 686 | ActionMap::iterator found = names_to_actions.find(namestr); 687 | if (found != e) { 688 | return found->second; 689 | } 690 | return 0; 691 | } 692 | 693 | //---------------------------------------------------------------------------- 694 | 695 | 696 | void QGLViewerWidget::del_draw_mode(const std::string& _s) 697 | { 698 | QString cmp = _s.c_str(); 699 | QList actions_ = popup_menu_->actions(); 700 | QList::iterator it=actions_.begin(), e=actions_.end(); 701 | for(; it!=e; ++it) { 702 | if ((*it)->text() == cmp) { break; } 703 | } 704 | 705 | #if _DEBUG 706 | assert( it != e ); 707 | #else 708 | if ( it == e ) 709 | return; 710 | #endif 711 | 712 | popup_menu_->removeAction(*it); 713 | //QActionGroup *grp = draw_modes_group_; 714 | 715 | } 716 | 717 | 718 | //---------------------------------------------------------------------------- 719 | 720 | 721 | void QGLViewerWidget::slotDrawMode(QAction* _mode) 722 | { 723 | // save draw mode 724 | draw_mode_ = _mode->data().toInt(); 725 | updateGL(); 726 | 727 | // check selected draw mode 728 | //popup_menu_->setItemChecked(draw_mode_, true); 729 | } 730 | 731 | 732 | //---------------------------------------------------------------------------- 733 | 734 | 735 | double QGLViewerWidget::performance() 736 | { 737 | setCursor( Qt::WaitCursor ); 738 | 739 | double fps(0.0); 740 | 741 | makeCurrent(); 742 | glMatrixMode(GL_MODELVIEW); 743 | glPushMatrix(); 744 | 745 | OpenMesh::Utils::Timer timer; 746 | 747 | unsigned int frames = 60; 748 | const float angle = 360.0/(float)frames; 749 | unsigned int i; 750 | Vec3f axis; 751 | 752 | glFinish(); 753 | 754 | timer.start(); 755 | for (i=0, axis=Vec3f(1,0,0); iprocessEvents(); 760 | 761 | timer.cont(); 762 | for (i=0, axis=Vec3f(0,1,0); iprocessEvents(); 767 | 768 | timer.cont(); 769 | for (i=0, axis=Vec3f(0,0,1); i fbuffer(3*w*h); 798 | 799 | qApp->processEvents(); 800 | makeCurrent(); 801 | updateGL(); 802 | glFinish(); 803 | 804 | glReadBuffer( buffer ); 805 | glPixelStorei(GL_PACK_ALIGNMENT, 1); 806 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 807 | paintGL(); 808 | glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &fbuffer[0] ); 809 | 810 | unsigned int x,y,offset; 811 | 812 | for (y=0; y