pax_global_header00006660000000000000000000000064132402172540014512gustar00rootroot0000000000000052 comment=75e935711da6ee1e081a242af76642e3a9fc6de3 mm3d-master/000077500000000000000000000000001324021725400132075ustar00rootroot00000000000000mm3d-master/.gitignore000066400000000000000000000001051324021725400151730ustar00rootroot00000000000000Makefile Makefile.in *.o *.a *.qm *.moc.* *.base.* .deps .*.swp tags mm3d-master/.travis.yml000066400000000000000000000004231324021725400153170ustar00rootroot00000000000000language: cpp sudo: false compiler: - gcc - clang script: ./autosetup.sh && ./configure && make addons: apt: packages: - libgl1-mesa-dev - qtbase5-dev - qtbase5-dev-tools - qttools5-dev-tools - libqt5opengl5-dev - libhtml-template-perl mm3d-master/AUTHORS000066400000000000000000000007201324021725400142560ustar00rootroot00000000000000Primary development: Kevin Worcester http://www.misfitcode.com/misfitmodel3d/contact.html Texture reload and Snap Together command: Johannes Kroll Various bug fixes and feature enhancements: Ainsley Pereira Initial Win32 Port Patch: Georg Hennig http://www.hennigbuam.de/georg/ Initial MD3 Filter: Russell Valentine http://coldstonelabs.org/ Various MD3 Filter improvements and maintainence: Zack Middleton http://clover.moe/ mm3d-master/CODE000066400000000000000000000031351324021725400136460ustar00rootroot00000000000000Quick guide to the MM3D code. Directories: src -- All source code libmm3d -- Low-level 3D functionality, model/texture handling mm3dcore -- Core application code depui -- Custom UI widgets for 3D drawing, used by many UI elements qtui -- User interface files (Qt's .ui files) implui -- Code that implements the user interface functionality commands -- Geometry menu commands tools -- Toolbar tools pixmap -- Icons used by mm3d doc -- Online documentation, HTML format i18n -- Internationalization files man -- Manpage desktop -- Desktop icons and config files util -- Utilities for building plugins -- Place-holder for unpacking and building plugins In general, the most interesting code is in src/libmm3d, src/tools, and src/commands for model manipulation and src/implui for user interface. About half of the code is in src/libmm3d, and about half of the code in src/libmm3d is in the model class (model.h, model.cc, model_*.cc). You can use src/maketags.sh to make ctags files for the source tree. Some development options for ./configure: --enable-debug=[yes/no/cov] The yes and no options turn debug information on and off. The cov option turns on debugging and coverage information. --enable-profile=[yes/no/core] The yes and no options turn profiling information on and off. The core option turns on profiling just for the application libraries (not the User Interface). mm3d-master/COPYING000066400000000000000000000436151324021725400142530ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mm3d-master/ChangeLog000066400000000000000000000333361324021725400147710ustar00rootroot00000000000000Changes for 1.3.9 Switch from Qt4 to Qt5 Make animation loop a per-animation setting that is saved in .mm3d files (mm3d format is now 1.7) Allow user to set fixed grid Fix incorrect texture rending for materials that share GL textures Fix insertFrameAnimFrame when frame is not at end Fix saving MD3 models with no frame animations Add a dialog to confirm saving a 3 part MD3 player model (before it always assumed yes) Made MD3 player support more general Read animation names / looping from animation.cfg (names fallback to Quake 3 ones if missing) Write animation names / looping from model animations instead of using a hard coded list Save all unknown points (e.g., not tag_torso, tag_head, or tag_weapon) as tags in all model parts Added support for "ALL_" (legs, torso, head) and "HEAD_" animation prefixes Don't require tag_weapon to export a MD3 player model Store options from animation.cfg in meta data "MD3_CFG_(keyword)" "(value)" instead of special handling for 'sex','footsteps','headoffset', 'fixedtorso','fixedlegs' which were stored as MD3_(keyword). MD3_sex, MD3_footsteps, etc are still supported for saving Add support for animation names to be at the beginning of each animation line in animation.cfg. Meta data "MD3_AnimKeyword" "1". Automatically detected when loading animation.cfg Allow disabling writing sync warnings in MD3 player animation.cfg using meta data "MD3_NoSyncWarning" "1". This is not automatically detected when loading animation.cfg Add support for Elite Force (Single Player) animation.cfg loop numbering style 0=loop all frames, -1=don't loop. Meta data "MD3_EliteLoop" "1". Automatically detected when loading animation.cfg Add support for loading / saving Quake III: Team Arena players Save point "tag_flag" in (only) the torso model Handle new Q3TA torso animations after legs in animation.cfg Add support for loading / saving Turtle Arena players Note: Exporting existing mm3d models to Quake 3 MD3 players requires setting the correct names and loop on animations. Changes for 1.3.8 Don't report power of two warning for background images Allow undo for texture coordinate vertex selection Rotate texture coordinates Horizontal/vertical flip texture coordinates Allow user to set color of texture coordinate lines and selection vertices. Include hidden triangles in BSP tree calculation, but don't render hidden triangles Change Hide Unselected so that it operates on the face level rather than face and vertex Add group clean-up window that removes identical/unused groups and materials Show dimensions of selected geometry in context panel Added grid unit distance to status bar In MD3, use anim name + frame num for frame name on export Use QString::toDouble instead of atof for localization reasons Fix incorrect group/texture mapping for copy/paste Fix viewport drawing mode so that it is applied to loaded models Fix texture rendering after deleted textures (off by one on greater index) Fix to draw proper normals for ungrouped geometry in skeletal animations Fix to prevent selection of hidden faces when using the "ignore back-facing" option Fix broken shortcuts on geometry sub-menus Fix coverage build/autoconf Fix MD2 export (vertex/texture coord indices) Fix relative path to parent dir for textures in OBJ format Fix cursor, reset coords, and zoom on texture coordinates window Fix help links on Windows Fix several compilation warnings Changes for 1.3.7 Added "Apply to selected" for Transform Model Export Selected (geometry, joints, points, and textures) Set exact position of rotate point for rotate tool More complete version support for Cal3D (700 through 1200) Read compressed animations in Cal3D Report error if saving MD2 or MD3 with faces that are not assigned to a group Fix to dissallow primitives additions using subdivide or addPoint Fix interpolation bug where rotation was not taking the shortest path to the new orientation Have a minimum animation redraw of 20 fps to show interpolation on slow animations Performance fixes for normal calculation (about 40% speed improvement) Performance fixes for MD3 loading (about 8x speed improvement) Added --enable-profile to ./configure Added --language to override the system locale Prevent select connected from selecting hidden faces Do not perform selection in frame animation mode if there are no animations Changed poly tool's "Fan" checkbox into a Strip/Fan combo box Implemented new equiv test and split CompareBits into CompareParts and PartProperties Changes for 1.3.6 Save/restore window size Include projection in frame all/selected command Open projection window from group and projection properties panels Allow multiple multiple bone joints for MS3D (subversions 1 and 2) Initial Cal3D support Better MD3_PATH handling Get MD3_PATH from shaders as well as model header Allow separate MD3_PATH for each shader Corrected capitalization for "Normals Face Out" command Split keyboard shortcut for flip front/back (backslash) view and flip ortho/persp (backtick) Added "Delete" button to animation model panel Redraw animation when loop is enabled/disabled (affects interpolation) Replaced lex/yacc code with custom preferences parser lex/yacc parser was having parse failures on some archs Allow MD2 texture coordinates to go outside of 0.0 to 1.0 range Report error if MD2 has more than one assigned material Remove trailing underscore on MD2 animation names Updated configuration for newer autoconf (2.61) and automake (1.9) Remember last skeletal/frame selection for new animation window Stop playing animation when a new animation is added. Error message when attempting to paste animation frame of wrong type Fixed bug where an influences with a weight of 0 has no influence, rather than placing the influenced object at the origin Fixed interpolation problem with translation keyframes on looped animations Fixed translation of animation name copy/split in animation sets window Fixed initial rotation of points for frame animations Other misc. translation fixes Added ../i18n to search path for translation files Treat unhandled backslashes in preferences as regular backslashes Changed error message on uknown file type to indicate it is probably a file extension problem Add ".mm3d" at save time if filename does not have an extension Use model vertex and point list sizes for writing frame animation data instead of using the size of the lists in the animation frames Added some sanity checking to MM3D loading code Removed several unused modules Added shell script for making source code tags Changes for 1.3.5 Re-organized menus Added "Rotate" tool in texture coordinate window Added "Face Out" command to make triangle normals point outward from enclosed hulls Added File|Export... to save without changing working filename or clearing unsaved flag Restrict Save and Save As to types with more complete support (everything else must use "Export...") Added Copy/Paste selected keyframe (for skeletal and frame) Added toolbar option on proj tool to create specific projection type Write texture coordinates for MM3D even if there are no materials MM3D no longer uses packed structs for mm3d, ms3d, tga, and pcx formats Improved material support for COB export Animation using Quaternion interpolation (prevent strange rotations when rotating on more than one axis) Fixed animation image export Fixed "Clear Animation Frame" for skeletal (broken when anim window was make dockable) Fix (hack) for Perspective label on all viewports Fixes for projection mapping at vertical extremes MD3 fixes: save case-insensitive animation names, cancel load if user selects "cancel" on player model Changes for 1.3.4 Support for internationalization Initial Slovak translation Show tool key accelerators in toolbar tool tip Rename bone joints and points from properties context panel Automatic bone joint assignment Extrude tool Option to create sphere from center Option to create torus from center Bring non-modal dialogs to front on open request when already open Fixes for MD2 (rotate orientation to match MM3D, prevent inversion of left/right, don't require animations to save/load), use MD2_PATH meta data for skin path instead of always assuming player model Fix for empty joint weight boxes Fix for starting in animation mode with animation toolbar hidden Changes for 1.3.3a Compilation fix for 64-bit architectures Changes for 1.3.3 Global transforms (translate, rotate, scale, arbitrary matrix) Disabled Lua by default Plane projection mapping Rotation on center of 3D viewport rather than origin Allow group material change from group properties panel Open group, material window from properties panel Can use orthographic projection from any angle (including tools) Can use Ctrl+Keyboard and Ctrl+ScrollButtons to rotate Rotate on Z axis (Ctrl+Mouse Wheel or Ctrl+Plus/Minus) Rotating fixed orthographic view switches to free orthographic automatically Hot key for saving and restoring viewport (Ctrl+Number to save, Number to restore) Tool to drag vertex on triangle Use tool keyboard shortcuts in texture coord window (Select Vertex, Move, Scale) Made texture coordinate window non-modal Texture coordinate window shows all selected faces (even if they do not belong to the same group) Scale tool in texture coordinate window has options for keeping aspect ratio and scaling from center Use Qt for drawing text in viewport instead of GLXFont (more portable) Fixed crash on alpha blending for non-texture materials Fixed OBJ material file creation on Win32 Fixed render menu selection indicators in Qt4/Win32 Changes for 1.3.2 Added "Influences Menu", all non-animation joint functions moved here Vertices and points can be assigned to multiple weighted bone joints Added "Paint Texture" window that saves a texture with the faces mapped onto it so that it can be painted over with a paint program Sphere and Cylinder mapping (Texture projection) Pan and zoom on texture coordinate edit window Keyboard shortcut customization (text file) Moved rendering options into a submenu of the View menu Added render option to turn off drawing of back-facing polygons Rotate tool rotation point defaults to center of selected objects Can create a new group by selecting "" in the group context panel Vertices can be created individually Made "Snap to Vertex" apply to bone joints, points, and projections Prevent viewport zoom/pan changes while tool is active Fixed MD3 crash on save without animations Fixed MD3 texture paths Fixed texture coordinates in MD2 for non-square skin images Fixed undo/redo selection on polygon tool Standardized enum declarations Standardized struct declarations Re-organized directory structure Corrected a typo in the View Window documentation Purge intermediate status bar messages if queue is too long (error messages not purged) Updated MM3D format documentation to include Points and Frame Anim Points Updated copyright dates Changes for 1.3.1 Added initial MD3 support (Initial filter written by Russell Valentine) Added Boolean operations (Union, Subtraction, Intersection) Added Simplify Mesh command Tint selected faces (uses lighting) User-defined viewport grid settings Allow setting multiple joint rotations at once (experimental) Allow changing/removing a texture on an existing material Added point rotation to properties window Added joint keyframe rotation to properties window Added points to the status bar primitive count Added .TXT model file format Added .RAW texture file format Use entire texture frame for 3D texture preview Do not exit on preferences parse failure Fixed looping animation frame time bug Fixed bolt point rotation and translation on model merge Fix for NaN in Matrix::getRotation() Fixed scoping error for gcc 4.1.1 Added virtual destructor for Model::Observer Changes for 1.3.0 (from 1.2.0-final) Snap to Grid Snap to Vertex Converted animation window to smaller, dockable window Added context-sensitive panel for editing position and group properties (more functionality to come) See View -> Show Properties Edge Turn command Edge Divide command Cap holes command Fixes for ./configure with 64-bit libraries Fixes for 64-bit safe (draw context, and pointer debug output) Initial bolt point support Initial .cob and .dxf support (read/write geometry and materials) Fixed crash on calculateFrameNormals if animation is out of range Append underscore to MD2 animation names that end in numbers to prevent truncation of animation name Change MD2 loading code to remove trailing digits instead of truncating at the first digit Polygon tool creates triangle to face tool viewport Fix for Face select in Frame Animation mode (patch from Russell Valentine) Fix for MD2 GL commands section (terminate with 0) Fixed scaling for co-axial points (division by zero causing undefined coordinates) Removed qpixmap uic hack in the Makefile mm3d-master/INSTALL000066400000000000000000000254251324021725400142500ustar00rootroot00000000000000Misfit Model 3D Installation ============================ If you are running on Windows see INSTALL.WIN32. If you are running on a Unix-like system, installation instructions follow. Misfit Model 3D requires the following packages for proper operation. They are most likely already installed if you have a modern working Linux system. Qt (5.x) with OpenGL support https://download.qt.io/archive/qt/ OpenGL with GLU (probably Mesa if you are using Linux) http://www.mesa3d.org/ Even if you have these packages installed you may need to install development packages as well. These include header files which are needed to compile Misfit Model 3D. Often such packages are marked as -dev or -devel by your distribution. For example, sometimes Qt is broken up into a qt rpm and qt-devel rpm. In this case, you must have both installed. This program uses autoconf and automake for building from source. What this means is that if you are lucky you can install this program by running these commands at a shell prompt (terminal window): ./autosetup.sh ./configure make sudo make install On macOS, use the commands listed in the README to create an App Bundle instead. The default PREFIX (install location) is /usr/local. Files are installed in the following directories. PREFIX/bin - mm3d executable PREFIX/share/mm3d/plugins - plugins PREFIX/share/doc/mm3d - program documentation PREFIX/share/applications - program menu entry PREFIX/share/mimelnk/application - .mm3d file integration PREFIX/share/pixmaps - program menu icon PREFIX/share/man/man1 - program manual You can give ./configure arguments to change how the program is compiled. For example you can change the default install location (PREFIX) by specifying --prefix=PATH, where PATH is the new install location. If Qt is not detected and you have it installed, try using --with-Qt-dir to specify the directory where Qt is installed. In a default Qt installation this is what your QTDIR environment variable is set to. Include files are in $QTDIR/include and library files are in $QTDIR/lib. Sometimes development files are in separate paths completely, such as libs in /usr/lib/qt5 and headers in /usr/include/qt5. In this case use --with-Qt-include-dir=/usr/include/qt5 and --with-Qt-lib-dir=/usr/lib/qt5. If you want to link against a specific library of Qt you can use --with-Qt-lib=LIBRARY to specify the library. For example, if you want to force the multi-threaded Qt library, you would use --with-Qt-lib=qt-mt Use ./configure --help for a complete list of options. If you need installation help you can post on the discussion forum: https://forum.clover.moe Below are generic instructions for installing programs using autoconf and automake. They are provided for reference if you need more help using ./configure. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.in' is used to create `configure' by a program called `autoconf'. You only need `configure.in' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this: CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure Or on systems that have the `env' program, you can do it like this: env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PATH'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PATH', the package will use PATH as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=PATH' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `--host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields: CPU-COMPANY-SYSTEM See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the host type. If you are building compiler tools for cross-compiling, you can also use the `--target=TYPE' option to select the type of system they will produce code for and the `--build=TYPE' option to select the type of system on which you are compiling the package. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Operation Controls ================== `configure' recognizes the following options to control how it operates. `--cache-file=FILE' Use and save the results of the tests in FILE instead of `./config.cache'. Set FILE to `/dev/null' to disable caching, for debugging `configure'. `--help' Print a summary of the options to `configure', and exit. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `--version' Print the version of Autoconf used to generate the `configure' script, and exit. `configure' also accepts some other, not widely useful, options. mm3d-master/INSTALL.WIN32000066400000000000000000000041401324021725400150400ustar00rootroot00000000000000Misfit Model 3D Installation For Win32 ====================================== Misfit Model 3D may or may not run on Windows XP. It will not work on older versions. Misfit Model 3D for Win32 requires the mingw environment and the Open Source version of Qt 5 for Win32. To run binaries of mm3d you only need the qt and mingw DLLs, which are provided with the binary distribution. To build from source you must have a development environment set up with mingw and qt5. Note that plugins are not currently available on Windows. Binary Installation =================== Get the latest installer from the web site. It should have a filename like 'mm3d-X_X_X-win32-installer.exe'. Run the installer and select an install location. Optionally you may choose to enable file assciations with Misfit Model 3D. By default only .mm3d is associated. Prerequisites ============= You can get Qt 5.x here: https://download.qt.io/archive/qt/ You can get mingw using Qt 5's binary installer, or download and install mingw yourself from the official website: http://www.mingw.org/ You must have your QTDIR environment variable set to the root Qt directory (for example, C:\Qt\5.0.0). The Mingw and Qt bin directories must be in your path. Build Instructions ================== Once you have installed mingw and Qt, do the following steps: 1. Make sure QTDIR is set and mingw's bin directory and Qt's bin directory is in your PATH 2. Open a cmd prompt and go to the mm3d-X.X.X directory 3. Copy config.h.generic to config.h 4. Run 'mingw32-make -f Makefile.generic' Install Instructions ==================== 1. Run 'install.bat' from the mm3d-X.X.X directory. The install.bat file does not create any program menu or desktop shortcuts. If you want shortcuts you must create them manually, or use the binary installer. Optionally, you can install NSIS and put the qt and mingw dlls in your mm3d-X.X.X/dll directory and then build the installer. This will create shortcuts and some registry keys. You can get NSIS here: http://nsis.sourceforge.net/ mm3d-master/Makefile.am000066400000000000000000000120471324021725400152470ustar00rootroot00000000000000EXTRA_DIST = Makefile.generic \ config.h.generic \ cleanup.sh \ mm3d-win32-installer.nsi \ TRANSLATORS \ INSTALL.WIN32 \ install.bat \ mm3d.reg SUBDIRS = src plugins i18n doc desktop man DESTDIR = src MAC_APP = Misfit Model 3D.app define INFOPLIST CFBundleDevelopmentRegion en UTExportedTypeDeclarations UTTypeConformsTo public.data UTTypeIdentifier moe.clover.mm3dmodel UTTypeDescription MM3D model UTTypeIconFile mm3d UTTypeReferenceURL http://www.misfitcode.com/misfitmodel3d/olh_mm3dformat.html UTTypeTagSpecification public.filename-extension mm3d CFBundleDocumentTypes CFBundleTypeName MM3D model LSItemContentTypes moe.clover.mm3dmodel CFBundleTypeRole Editor LSHandlerRank Owner CFBundleTypeName Quake 2 model CFBundleTypeExtensions md2 CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleTypeName Quake 3 model CFBundleTypeExtensions md3 CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleTypeName Milkshape 3D model CFBundleTypeExtensions ms3d CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleTypeName Wavefront OBJ model CFBundleTypeExtensions obj CFBundleTypeRole Editor LSHandlerRank Alternate CFBundleExecutable ${PACKAGE} CFBundleIconFile ${PACKAGE} CFBundleIdentifier moe.clover.${PACKAGE} CFBundleInfoDictionaryVersion 6.0 CFBundleName Misfit Model 3D CFBundlePackageType APPL CFBundleShortVersionString ${VERSION} CFBundleSignature ???? CFBundleVersion ${VERSION} CGDisableCoalescedUpdates LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSHumanReadableCopyright Copyright © 2004-2008 Kevin Worcester, clover.moe fork © 2009-2018 Zack Middleton. NSPrincipalClass NSApplication endef export INFOPLIST $(PACKAGE).app: ${INSTALL} -d "$(MAC_APP)/Contents/MacOS/" ${INSTALL} -d "$(MAC_APP)/Contents/Resources/" ${INSTALL} -d "$(MAC_APP)/Contents/PlugIns/mm3d/1.3" ${INSTALL} -d "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/olh_images/screencaps/" ${INSTALL} -d "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/olh_images/tools/" ${INSTALL} -d "$(MAC_APP)/Contents/SharedSupport/mm3d/i18n/" ${INSTALL} -m 0755 "$(DESTDIR)/$(PACKAGE)" "$(MAC_APP)/Contents/MacOS/$(PACKAGE)" ${INSTALL} -m 0644 mm3d.icns "$(MAC_APP)/Contents/Resources/${PACKAGE}.icns" ${INSTALL} -m 0644 doc/html/*.html "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/" ${INSTALL} -m 0644 doc/html/olh_images/screencaps/*.png "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/olh_images/screencaps/" ${INSTALL} -m 0644 doc/html/olh_images/tools/*.png "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/olh_images/tools/" ${INSTALL} -m 0644 doc/html/olh_images/tools/*.jpg "$(MAC_APP)/Contents/SharedSupport/mm3d/doc/html/olh_images/tools/" ${INSTALL} -m 0644 i18n/*.qm "$(MAC_APP)/Contents/SharedSupport/mm3d/i18n/" echo "APPL????" > "$(MAC_APP)/Contents/PkgInfo" @echo "$$INFOPLIST" > "$(MAC_APP)/Contents/Info.plist" @echo "Wrote \"$(MAC_APP)/Contents/Info.plist\"" $(QT_MACDEPLOYQT) "$(MAC_APP)" mm3d-master/Makefile.generic000066400000000000000000000532001324021725400162620ustar00rootroot00000000000000# # Misfit Model 3D Makefile # # GNU Make required # COMPILE_PLATFORM=$(shell uname|sed -e s/_.*//|tr '[:upper:]' '[:lower:]'|sed -e 's/\//_/g') COMPILE_ARCH=$(shell uname -m | sed -e s/i.86/x86/) ifeq ($(COMPILE_PLATFORM),sunos) # Solaris uname and GNU uname differ COMPILE_ARCH=$(shell uname -p | sed -e s/i.86/x86/) endif ############################################################################# # # If you require a different configuration from the defaults below, create a # new file named "Makefile.local" in the same directory as this file and define # your parameters there. This allows you to change configuration without # causing problems with keeping up to date with the repository. # ############################################################################# -include Makefile.local ifeq ($(COMPILE_PLATFORM),cygwin) PLATFORM=mingw32 endif ifndef PLATFORM PLATFORM=$(COMPILE_PLATFORM) endif export PLATFORM ifeq ($(PLATFORM),mingw32) MINGW=1 endif ifeq ($(PLATFORM),mingw64) MINGW=1 endif ifeq ($(COMPILE_ARCH),powerpc) COMPILE_ARCH=ppc endif ifeq ($(COMPILE_ARCH),powerpc64) COMPILE_ARCH=ppc64 endif ifndef ARCH ARCH=$(COMPILE_ARCH) endif export ARCH ifneq ($(PLATFORM),$(COMPILE_PLATFORM)) CROSS_COMPILING=1 else CROSS_COMPILING=0 ifneq ($(ARCH),$(COMPILE_ARCH)) CROSS_COMPILING=1 endif endif export CROSS_COMPILING ifndef V V= endif ifndef BUILD BUILD=build endif bin_path=$(shell which $(1) 2> /dev/null) B=${BUILD}/${PLATFORM}-${ARCH} INSTALL=install MKDIR=mkdir -p ############################################################################# # SETUP AND BUILD -- MINGW ############################################################################# ifdef MINGW ifeq ($(CROSS_COMPILING),1) ifndef QT_BIN_DIR $(error Need to specify QT_BIN_DIR with native Qt5 executables for uic, moc, and lrelease) endif ifndef QT_INCLUDE_DIR $(error Need to specify QT_INCLUDE_DIR with MinGW Qt5 headers) endif ifndef QT_LIB_DIR $(error Need to specify QT_LIB_DIR with MinGW Qt5 libs) endif # If CC is already set to something generic, we probably want to use # something more specific ifneq ($(findstring $(strip $(CC)),cc gcc),) CC= endif ifneq ($(findstring $(strip $(CXX)),g++),) CXX= endif # We need to figure out the correct gcc and windres ifeq ($(ARCH),x86_64) MINGW_PREFIXES=amd64-mingw32msvc x86_64-w64-mingw32 endif ifeq ($(ARCH),x86) MINGW_PREFIXES=i586-mingw32msvc i686-w64-mingw32 i686-pc-mingw32 endif ifndef CC CC=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ $(call bin_path, $(MINGW_PREFIX)-gcc))) endif ifndef CXX CXX=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ $(call bin_path, $(MINGW_PREFIX)-g++))) endif ifndef WINDRES WINDRES=$(strip $(foreach MINGW_PREFIX, $(MINGW_PREFIXES), \ $(call bin_path, $(MINGW_PREFIX)-windres))) endif TOOLS_BINEXT= else # Some MinGW installations define CC to cc, but don't actually provide cc, # so check that CC points to a real binary and use gcc if it doesn't ifeq ($(call bin_path, $(CC)),) CC=gcc endif ifndef CXX CC=g++ endif ifndef WINDRES WINDRES=windres endif TOOLS_BINEXT=.exe endif ifeq ($(CC),) $(error Cannot find a suitable cross compiler for $(PLATFORM)) endif ifndef QTDIR QTDIR=C:/Qt/5.0.0 endif ifndef QT_BIN_DIR QT_BIN_DIR=${QTDIR}/bin endif ifndef QT_INCLUDE_DIR QT_INCLUDE_DIR=${QTDIR}/include endif ifndef QT_LIB_DIR QT_LIB_DIR=${QTDIR}/lib endif ifndef QT_LIBS QT_LIBS=-lQt5Core -lQt5Gui -lQt5Widgets -lQt5OpenGL endif LINK=-L${QT_LIB_DIR} ${QT_LIBS} -mwindows -lopengl32 -lglu32 -static-libgcc -static-libstdc++ BINEXT=.${ARCH}.exe else # ifeq mingw ############################################################################# # SETUP AND BUILD -- MAC OS X ############################################################################# ifeq ($(PLATFORM),darwin) ifndef PREFIX PREFIX=/usr/local endif ifndef QTDIR QTDIR=/usr/local/Cellar/qt/5.10.0_1 endif ifndef QT_BIN_DIR QT_BIN_DIR=${QTDIR}/bin endif ifndef QT_INCLUDE_DIR QT_INCLUDE_DIR=${QTDIR}/include endif ifndef QT_LIB_DIR QT_LIB_DIR=${QTDIR}/lib endif ifndef QT_FRAMEWORKS_DIR QT_FRAMEWORKS_DIR=${QTDIR}/Frameworks endif ifndef QT_LIBS QT_LIBS=-framework QtCore -framework QtGui -framework QtWidgets -framework QtOpenGL endif LINK=-F${QT_FRAMEWORKS_DIR} -L${QT_LIB_DIR} ${QT_LIBS} -framework OpenGl # Qt5 requires C++11 BASE_FLAGS+=-std=c++11 -stdlib=libc++ ifeq ($(ARCH),x86) BASE_FLAGS += -m32 endif BASE_FLAGS += -DPREFIX="\"$(PREFIX)\"" -DIS_OSX BINEXT=.${ARCH} TOOLS_BINEXT= else # ifeq darwin ############################################################################# # SETUP AND BUILD -- LINUX ############################################################################# ifndef PREFIX PREFIX=/usr/local endif ifdef QTDIR ifndef QT_BIN_DIR QT_BIN_DIR=${QTDIR}/bin endif ifndef QT_INCLUDE_DIR QT_INCLUDE_DIR=${QTDIR}/include endif ifndef QT_LIB_DIR QT_LIB_DIR=${QTDIR}/lib endif else ifndef QT_BIN_DIR ifeq ($(ARCH),x86) QT_BIN_DIR=/usr/lib/i386-linux-gnu/qt5/bin else QT_BIN_DIR=/usr/lib/$(ARCH)-linux-gnu/qt5/bin endif endif ifndef QT_INCLUDE_DIR ifeq ($(ARCH),x86) QT_INCLUDE_DIR=/usr/include/i386-linux-gnu/qt5 else QT_INCLUDE_DIR=/usr/include/$(ARCH)-linux-gnu/qt5 endif endif ifndef QT_LIB_DIR ifeq ($(ARCH),x86) QT_LIB_DIR=/usr/lib/i386-linux-gnu else QT_LIB_DIR=/usr/lib/$(ARCH)-linux-gnu endif endif endif ifndef QT_LIBS QT_LIBS=-lQt5Core -lQt5Gui -lQt5Widgets -lQt5OpenGL endif LINK=-L${QT_LIB_DIR} ${QT_LIBS} -lGLU -lGL -ldl ifeq ($(ARCH),x86) # linux32 make ... BASE_FLAGS += -m32 else ifeq ($(ARCH),ppc64) BASE_FLAGS += -m64 endif endif BASE_FLAGS += -DPREFIX="\"$(PREFIX)\"" BINEXT=.${ARCH} TOOLS_BINEXT= endif # darwin endif # mingw ifndef QT_BIN_DIR $(error QT_BIN_DIR is not set) endif ifndef QT_INCLUDE_DIR $(error QT_INCLUDE_DIR is not set) endif ifndef UIC UIC=${QT_BIN_DIR}/uic${TOOLS_BINEXT} endif ifndef MOC MOC=${QT_BIN_DIR}/moc${TOOLS_BINEXT} endif ifndef LRELEASE LRELEASE=${QT_BIN_DIR}/lrelease${TOOLS_BINEXT} endif #CXXFLAGS=-Wall -g3 CXXFLAGS=-O2 ${BASE_FLAGS} -fno-math-errno -fPIC -I${QT_INCLUDE_DIR} -DMM3D_EDIT -I. -I./src -I./src/libmm3d -I./src/mm3dcore -I./src/depui -I./src/qtui -I./src/implui -I./src/commands -I./src/tools -I${B}/depui -I${B}/qtui -I${B}/implui -I${B}/commands DEFS= BIN=${B} LIB_OBJ= \ ${B}/libmm3d/bsptree.o \ ${B}/libmm3d/cal3dfilter.o \ ${B}/libmm3d/cmdlinemgr.o \ ${B}/libmm3d/cobfilter.o \ ${B}/libmm3d/datadest.o \ ${B}/libmm3d/datasource.o \ ${B}/libmm3d/filedatadest.o \ ${B}/libmm3d/filedatasource.o \ ${B}/libmm3d/memdatadest.o \ ${B}/libmm3d/memdatasource.o \ ${B}/libmm3d/dxffilter.o \ ${B}/libmm3d/filefactory.o \ ${B}/libmm3d/filtermgr.o \ ${B}/libmm3d/glmath.o \ ${B}/libmm3d/log.o \ ${B}/libmm3d/lwofilter.o \ ${B}/libmm3d/md2filter.o \ ${B}/libmm3d/md3filter.o \ ${B}/libmm3d/mesh.o \ ${B}/libmm3d/misc.o \ ${B}/libmm3d/mlocale.o \ ${B}/libmm3d/mm3dfilter.o \ ${B}/libmm3d/mm3dport.o \ ${B}/libmm3d/mm3dreg.o \ ${B}/libmm3d/model.o \ ${B}/libmm3d/model_anim.o \ ${B}/libmm3d/model_bool.o \ ${B}/libmm3d/model_copy.o \ ${B}/libmm3d/model_draw.o \ ${B}/libmm3d/model_group.o \ ${B}/libmm3d/model_influence.o \ ${B}/libmm3d/model_inner.o \ ${B}/libmm3d/model_insert.o \ ${B}/libmm3d/model_meta.o \ ${B}/libmm3d/model_ops.o \ ${B}/libmm3d/model_print.o \ ${B}/libmm3d/model_proj.o \ ${B}/libmm3d/model_select.o \ ${B}/libmm3d/model_texture.o \ ${B}/libmm3d/modelfilter.o \ ${B}/libmm3d/modelstatus.o \ ${B}/libmm3d/modelundo.o \ ${B}/libmm3d/modelutil.o \ ${B}/libmm3d/ms3dfilter.o \ ${B}/libmm3d/msg.o \ ${B}/libmm3d/objfilter.o \ ${B}/libmm3d/pcxtex.o \ ${B}/libmm3d/rawtex.o \ ${B}/libmm3d/texmgr.o \ ${B}/libmm3d/texscale.o \ ${B}/libmm3d/texture.o \ ${B}/libmm3d/tgatex.o \ ${B}/libmm3d/triprim.o \ ${B}/libmm3d/txtfilter.o \ ${B}/libmm3d/undo.o \ ${B}/libmm3d/undomgr.o \ ${B}/libmm3d/weld.o \ MM3D_UI= \ ${B}/qtui/alignwin.base.h \ ${B}/qtui/animconvertwin.base.h \ ${B}/qtui/animexportwin.base.h \ ${B}/qtui/animsetwin.base.h \ ${B}/qtui/animwidget.base.h \ ${B}/qtui/autoassignjointwin.base.h \ ${B}/qtui/backgroundselect.base.h \ ${B}/qtui/backgroundwin.base.h \ ${B}/qtui/boolwin.base.h \ ${B}/qtui/contextgroup.base.h \ ${B}/qtui/contextinfluences.base.h \ ${B}/qtui/contextname.base.h \ ${B}/qtui/contextposition.base.h \ ${B}/qtui/contextprojection.base.h \ ${B}/qtui/contextrotation.base.h \ ${B}/qtui/extrudewin.base.h \ ${B}/qtui/globalmenubar.base.h \ ${B}/qtui/groupclean.base.h \ ${B}/qtui/groupwin.base.h \ ${B}/qtui/helpwin.base.h \ ${B}/qtui/jointwin.base.h \ ${B}/qtui/painttexturewin.base.h \ ${B}/qtui/pointwin.base.h \ ${B}/qtui/projectionwin.base.h \ ${B}/qtui/keyvaluewin.base.h \ ${B}/qtui/mapdirection.base.h \ ${B}/qtui/mergewin.base.h \ ${B}/qtui/metawin.base.h \ ${B}/qtui/modelview.base.h \ ${B}/qtui/newanim.base.h \ ${B}/qtui/cal3dprompt.base.h \ ${B}/qtui/ms3dprompt.base.h \ ${B}/qtui/objprompt.base.h \ ${B}/qtui/pluginwin.base.h \ ${B}/qtui/rgbawin.base.h \ ${B}/qtui/statusbar.base.h \ ${B}/qtui/texturecoord.base.h \ ${B}/qtui/textwin.base.h \ ${B}/qtui/texwin.base.h \ ${B}/qtui/transformwin.base.h \ ${B}/qtui/valuewin.base.h \ ${B}/qtui/viewportsettings.base.h MM3D_MOC= \ ${B}/implui/alignwin.moc.cc \ ${B}/implui/aboutwin.moc.cc \ ${B}/implui/animconvertwin.moc.cc \ ${B}/implui/animexportwin.moc.cc \ ${B}/implui/animsetwin.moc.cc \ ${B}/implui/animwidget.moc.cc \ ${B}/implui/animwin.moc.cc \ ${B}/implui/autoassignjointwin.moc.cc \ ${B}/implui/backgroundselect.moc.cc \ ${B}/implui/backgroundwin.moc.cc \ ${B}/implui/boolpanel.moc.cc \ ${B}/implui/boolwin.moc.cc \ ${B}/implui/contextinfluences.moc.cc \ ${B}/implui/contextname.moc.cc \ ${B}/implui/contextpanel.moc.cc \ ${B}/implui/contextposition.moc.cc \ ${B}/implui/contextprojection.moc.cc \ ${B}/implui/contextrotation.moc.cc \ ${B}/tools/cubetoolwidget.moc.cc \ ${B}/tools/cylindertoolwidget.moc.cc \ ${B}/tools/ellipsetoolwidget.moc.cc \ ${B}/depui/errorobj.moc.cc \ ${B}/implui/extrudewin.moc.cc \ ${B}/implui/globalmenubar.moc.cc \ ${B}/implui/groupclean.moc.cc \ ${B}/implui/groupwin.moc.cc \ ${B}/implui/helpwin.moc.cc \ ${B}/implui/jointwin.moc.cc \ ${B}/implui/painttexturewin.moc.cc \ ${B}/implui/pointwin.moc.cc \ ${B}/implui/projectionwin.moc.cc \ ${B}/implui/keyvaluewin.moc.cc \ ${B}/implui/licensewin.moc.cc \ ${B}/implui/mergewin.moc.cc \ ${B}/implui/metawin.moc.cc \ ${B}/implui/mview.moc.cc \ ${B}/depui/modelviewport.moc.cc \ ${B}/implui/newanim.moc.cc \ ${B}/implui/cal3dprompt.moc.cc \ ${B}/implui/ms3dprompt.moc.cc \ ${B}/implui/objprompt.moc.cc \ ${B}/implui/pluginwin.moc.cc \ ${B}/tools/polytoolwidget.moc.cc \ ${B}/tools/projtoolwidget.moc.cc \ ${B}/implui/rgbawin.moc.cc \ ${B}/tools/scaletoolwidget.moc.cc \ ${B}/tools/selectfacetoolwidget.moc.cc \ ${B}/implui/spherifywin.moc.cc \ ${B}/implui/statusbar.moc.cc \ ${B}/depui/textureframe.moc.cc \ ${B}/implui/texturecoord.moc.cc \ ${B}/depui/texwidget.moc.cc \ ${B}/implui/texwin.moc.cc \ ${B}/implui/transformwin.moc.cc \ ${B}/implui/valuewin.moc.cc \ ${B}/implui/viewportsettings.moc.cc \ ${B}/implui/viewpanel.moc.cc \ ${B}/implui/viewwin.moc.cc \ MM3D_MOC_OBJ= \ ${B}/implui/alignwin.moc.o \ ${B}/implui/aboutwin.moc.o \ ${B}/implui/animconvertwin.moc.o \ ${B}/implui/animexportwin.moc.o \ ${B}/implui/animsetwin.moc.o \ ${B}/implui/animwidget.moc.o \ ${B}/implui/animwin.moc.o \ ${B}/implui/autoassignjointwin.moc.o \ ${B}/implui/backgroundselect.moc.o \ ${B}/implui/backgroundwin.moc.o \ ${B}/implui/boolpanel.moc.o \ ${B}/implui/boolwin.moc.o \ ${B}/implui/contextgroup.moc.o \ ${B}/implui/contextinfluences.moc.o \ ${B}/implui/contextname.moc.o \ ${B}/implui/contextpanel.moc.o \ ${B}/implui/contextposition.moc.o \ ${B}/implui/contextprojection.moc.o \ ${B}/implui/contextrotation.moc.o \ ${B}/tools/cubetoolwidget.moc.o \ ${B}/tools/cylindertoolwidget.moc.o \ ${B}/tools/ellipsetoolwidget.moc.o \ ${B}/tools/rotatetoolwidget.moc.o \ ${B}/tools/torustoolwidget.moc.o \ ${B}/tools/toolwidget.moc.o \ ${B}/depui/errorobj.moc.o \ ${B}/implui/extrudewin.moc.o \ ${B}/implui/globalmenubar.moc.o \ ${B}/implui/groupclean.moc.o \ ${B}/implui/groupwin.moc.o \ ${B}/implui/helpwin.moc.o \ ${B}/implui/jointwin.moc.o \ ${B}/implui/painttexturewin.moc.o \ ${B}/implui/pointwin.moc.o \ ${B}/implui/projectionwin.moc.o \ ${B}/implui/keyvaluewin.moc.o \ ${B}/implui/licensewin.moc.o \ ${B}/implui/mapdirection.moc.o \ ${B}/implui/mergewin.moc.o \ ${B}/implui/metawin.moc.o \ ${B}/implui/mview.moc.o \ ${B}/depui/modelviewport.moc.o \ ${B}/implui/newanim.moc.o \ ${B}/implui/cal3dprompt.moc.o \ ${B}/implui/ms3dprompt.moc.o \ ${B}/implui/objprompt.moc.o \ ${B}/implui/pluginwin.moc.o \ ${B}/tools/polytoolwidget.moc.o \ ${B}/tools/projtoolwidget.moc.o \ ${B}/implui/rgbawin.moc.o \ ${B}/tools/scaletoolwidget.moc.o \ ${B}/tools/selectfacetoolwidget.moc.o \ ${B}/implui/spherifywin.moc.o \ ${B}/implui/statusbar.moc.o \ ${B}/depui/textureframe.moc.o \ ${B}/implui/texturecoord.moc.o \ ${B}/depui/texwidget.moc.o \ ${B}/implui/texwin.moc.o \ ${B}/implui/transformwin.moc.o \ ${B}/implui/valuewin.moc.o \ ${B}/implui/viewportsettings.moc.o \ ${B}/implui/viewpanel.moc.o \ ${B}/implui/viewwin.moc.o \ MM3D_OBJ= \ ${B}/src/3dm.o \ ${B}/mm3dcore/3dmprefs.o \ ${B}/implui/aboutwin.o \ ${B}/mm3dcore/align.o \ ${B}/commands/aligncmd.o \ ${B}/implui/alignwin.o \ ${B}/mm3dcore/allocstats.o \ ${B}/implui/animconvertwin.o \ ${B}/implui/animexportwin.o \ ${B}/implui/animsetwin.o \ ${B}/implui/animwidget.o \ ${B}/implui/animwin.o \ ${B}/tools/atrfartool.o \ ${B}/tools/atrneartool.o \ ${B}/commands/backgroundcmd.o \ ${B}/implui/autoassignjointwin.o \ ${B}/implui/backgroundselect.o \ ${B}/implui/backgroundwin.o \ ${B}/implui/boolpanel.o \ ${B}/implui/boolwin.o \ ${B}/implui/contextgroup.o \ ${B}/implui/contextinfluences.o \ ${B}/implui/contextname.o \ ${B}/implui/contextpanel.o \ ${B}/implui/contextposition.o \ ${B}/implui/contextprojection.o \ ${B}/implui/contextrotation.o \ ${B}/mm3dcore/contextwidget.o \ ${B}/mm3dcore/contextpanelobserver.o \ ${B}/tools/bgmovetool.o \ ${B}/tools/bgscaletool.o \ ${B}/mm3dcore/bounding.o \ ${B}/mm3dcore/cmdline.o \ ${B}/mm3dcore/cmdmgr.o \ ${B}/mm3dcore/command.o \ ${B}/commands/capcmd.o \ ${B}/commands/copycmd.o \ ${B}/tools/cubetool.o \ ${B}/tools/cubetoolwidget.o \ ${B}/tools/cylindertool.o \ ${B}/tools/cylindertoolwidget.o \ ${B}/mm3dcore/decal.o \ ${B}/mm3dcore/decalmgr.o \ ${B}/commands/deletecmd.o \ ${B}/commands/dupcmd.o \ ${B}/commands/edgedivcmd.o \ ${B}/commands/edgeturncmd.o \ ${B}/tools/ellipsetool.o \ ${B}/tools/ellipsetoolwidget.o \ ${B}/tools/extrudetool.o \ ${B}/depui/errorobj.o \ ${B}/commands/extrudecmd.o \ ${B}/implui/extrudewin.o \ ${B}/commands/faceoutcmd.o \ ${B}/commands/flattencmd.o \ ${B}/commands/flipcmd.o \ ${B}/implui/globalmenubar.o \ ${B}/implui/groupclean.o \ ${B}/implui/groupwin.o \ ${B}/implui/helpwin.o \ ${B}/commands/hidecmd.o \ ${B}/commands/invertcmd.o \ ${B}/commands/invnormalcmd.o \ ${B}/commands/jointcmd.o \ ${B}/commands/pointcmd.o \ ${B}/commands/assignjointcmd.o \ ${B}/tools/jointtool.o \ ${B}/tools/pointtool.o \ ${B}/tools/projtool.o \ ${B}/implui/jointwin.o \ ${B}/implui/painttexturewin.o \ ${B}/implui/pointwin.o \ ${B}/implui/projectionwin.o \ ${B}/implui/keycfg.o \ ${B}/implui/keyvaluewin.o \ ${B}/implui/licensewin.o \ ${B}/mm3dcore/luaif.o \ ${B}/mm3dcore/luascript.o \ ${B}/commands/makefacecmd.o \ ${B}/implui/mapdirection.o \ ${B}/implui/mergewin.o \ ${B}/implui/metawin.o \ ${B}/tools/movetool.o \ ${B}/implui/msgqt.o \ ${B}/implui/mview.o \ ${B}/depui/modelviewport.o \ ${B}/commands/pastecmd.o \ ${B}/mm3dcore/pluginmgr.o \ ${B}/implui/newanim.o \ ${B}/implui/cal3dprompt.o \ ${B}/implui/ms3dprompt.o \ ${B}/implui/objprompt.o \ ${B}/implui/pluginwin.o \ ${B}/tools/polytool.o \ ${B}/tools/polytoolwidget.o \ ${B}/tools/projtoolwidget.o \ ${B}/mm3dcore/prefparse.o \ ${B}/mm3dcore/prefs.o \ ${B}/implui/qtmain.o \ ${B}/implui/qttex.o \ ${B}/tools/rectangletool.o \ ${B}/implui/rgbawin.o \ ${B}/mm3dcore/rotatepoint.o \ ${B}/commands/rotatetexcmd.o \ ${B}/tools/rotatetool.o \ ${B}/tools/scaletool.o \ ${B}/tools/scaletoolwidget.o \ ${B}/tools/selectfacetoolwidget.o \ ${B}/mm3dcore/scriptif.o \ ${B}/tools/selectbonetool.o \ ${B}/tools/selectpointtool.o \ ${B}/tools/selectprojtool.o \ ${B}/tools/selectconnectedtool.o \ ${B}/tools/selectfacetool.o \ ${B}/tools/selectgrouptool.o \ ${B}/tools/selectvertextool.o \ ${B}/tools/sheartool.o \ ${B}/commands/selectfreecmd.o \ ${B}/commands/simplifycmd.o \ ${B}/commands/snapcmd.o \ ${B}/commands/spherifycmd.o \ ${B}/implui/spherifywin.o \ ${B}/implui/statusbar.o \ ${B}/src/stdcmds.o \ ${B}/src/stdfilters.o \ ${B}/src/stdtexfilters.o \ ${B}/src/stdtools.o \ ${B}/commands/subdividecmd.o \ ${B}/mm3dcore/sysconf.o \ ${B}/depui/textureframe.o \ ${B}/implui/texturecoord.o \ ${B}/mm3dcore/texturetest.o \ ${B}/depui/texwidget.o \ ${B}/implui/texwin.o \ ${B}/implui/transformwin.o \ ${B}/implui/transimp.o \ ${B}/libmm3d/translate.o \ ${B}/mm3dcore/tool.o \ ${B}/mm3dcore/toolbox.o \ ${B}/mm3dcore/toolpoly.o \ ${B}/tools/rotatetoolwidget.o \ ${B}/tools/torustool.o \ ${B}/tools/torustoolwidget.o \ ${B}/tools/toolwidget.o \ ${B}/commands/unweldcmd.o \ ${B}/implui/valuewin.o \ ${B}/tools/vertextool.o \ ${B}/tools/dragvertextool.o \ ${B}/implui/viewportsettings.o \ ${B}/implui/viewpanel.o \ ${B}/implui/viewwin.o \ ${B}/implui/viewwin_influences.o \ ${B}/commands/weldcmd.o QMFILES = \ ${B}/i18n/mm3d_de.qm \ ${B}/i18n/mm3d_fr.qm \ ${B}/i18n/mm3d_sk.qm \ ${B}/i18n/mm3d_ref.qm \ ${B}/i18n/mm3d_bork.qm \ ${B}/i18n/qt_ar.qm \ ${B}/i18n/qt_cs.qm \ ${B}/i18n/qt_de.qm \ ${B}/i18n/qt_fr.qm \ ${B}/i18n/qt_iw.qm \ ${B}/i18n/qt_ru.qm \ ${B}/i18n/qt_sk.qm \ ${B}/i18n/qt_zh_CN.qm ifeq (${V},1) echo_cmd=@: Q= else echo_cmd=@echo Q=@ endif define DO_CC $(echo_cmd) "CC $<" $(Q)${CC} ${DEFS} -c $< -o $@ ${CXXFLAGS} endef define DO_CXX $(echo_cmd) "CXX $<" $(Q)${CXX} ${DEFS} -c $< -o $@ ${CXXFLAGS} endef define DO_UIC $(echo_cmd) "UIC $<" $(Q)${UIC} $< -o $@ endef define DO_MOC $(echo_cmd) "MOC $<" $(Q)${MOC} $< -o $@ endef define DO_LRELEASE $(echo_cmd) "LRELEASE $<" $(Q)${LRELEASE} $< -qm $@ endef .PHONY: all mm3d_ui mm3d_moc mm3d clean all: makedirs mm3d_ui mm3d_moc mm3d qmfiles makedirs: @if [ ! -d ${B} ];then ${MKDIR} ${B};fi @if [ ! -d ${B}/src ];then ${MKDIR} ${B}/src;fi @if [ ! -d ${B}/depui ];then ${MKDIR} ${B}/depui;fi @if [ ! -d ${B}/implui ];then ${MKDIR} ${B}/implui;fi @if [ ! -d ${B}/qtui ];then ${MKDIR} ${B}/qtui;fi @if [ ! -d ${B}/tools ];then ${MKDIR} ${B}/tools;fi @if [ ! -d ${B}/libmm3d ];then ${MKDIR} ${B}/libmm3d;fi @if [ ! -d ${B}/mm3dcore ];then ${MKDIR} ${B}/mm3dcore;fi @if [ ! -d ${B}/commands ];then ${MKDIR} ${B}/commands;fi @if [ ! -d ${B}/i18n ];then ${MKDIR} ${B}/i18n;fi mm3d_ui: ${MM3D_UI} mm3d_moc: ${MM3D_MOC} qmfiles: ${QMFILES} $(BIN)/mm3d${BINEXT}: ${MM3D_MOC_OBJ} ${LIB_OBJ} ${MM3D_OBJ} $(echo_cmd) "LINKING $(BIN)/mm3d${BINEXT}" ifdef MINGW $(Q)${WINDRES} src/icon.rc ${B}/icon.o $(Q)${CXX} ${CXXFLAGS} ${DEFS} -o $(BIN)/mm3d${BINEXT} ${MM3D_OBJ} ${MM3D_MOC_OBJ} ${LIB_OBJ} ${B}/icon.o ${LINK} else $(Q)${CXX} ${CXXFLAGS} ${DEFS} -o $(BIN)/mm3d${BINEXT} ${MM3D_OBJ} ${MM3D_MOC_OBJ} ${LIB_OBJ} ${LINK} endif mm3d: $(BIN)/mm3d${BINEXT} # FIXME: html docs are only created by autotools build system #$(INSTALL) -d "$(PREFIX)/share/doc/mm3d/html/" #$(INSTALL) -d "$(PREFIX)/share/doc/mm3d/html/olh_images/screencaps/" #$(INSTALL) -d "$(PREFIX)/share/doc/mm3d/html/olh_images/tools/" #${INSTALL} -m 0644 doc/html/*.html "$(PREFIX)/share/doc/mm3d/html/" #${INSTALL} -m 0644 doc/html/olh_images/screencaps/*.png "$(PREFIX)/share/doc/mm3d/html/olh_images/screencaps/" #${INSTALL} -m 0644 doc/html/olh_images/tools/*.png "$(PREFIX)/share/doc/mm3d/html/olh_images/tools/" #${INSTALL} -m 0644 doc/html/olh_images/tools/*.jpg "$(PREFIX)/share/doc/mm3d/html/olh_images/tools/" install: ifdef MINGW $(echo_cmd) "See install.bat" else $(INSTALL) -d "$(PREFIX)/bin" $(INSTALL) -m 0755 $(BIN)/mm3d${BINEXT} "$(PREFIX)/bin/mm3d" $(INSTALL) -d "$(PREFIX)/share/mm3d/i18n/" ${INSTALL} -m 0644 ${B}/i18n/*.qm "$(PREFIX)/share/mm3d/i18n/" $(INSTALL) -d "$(PREFIX)/share/applications/" $(INSTALL) -d "$(PREFIX)/share/mimelnk/application/" $(INSTALL) -d "$(PREFIX)/share/pixmaps/" ${INSTALL} -m 0644 desktop/mm3d.desktop "$(PREFIX)/share/applications/" ${INSTALL} -m 0644 desktop/x-mm3d.desktop "$(PREFIX)/share/mimelnk/application/" ${INSTALL} -m 0644 desktop/*.xpm "$(PREFIX)/share/pixmaps/" $(INSTALL) -d "$(PREFIX)/share/man/man1/" ${INSTALL} -m 0644 man/mm3d.1 "$(PREFIX)/share/man/man1/" endif installer: mm3d cp -r ../dll . cp -r ../imageformats . strip $(BIN)/mm3d${BINEXT} makensis mm3d-win32-installer.nsi ${B}/%.o: src/%.c $(DO_CC) ${B}/%.o: src/%.cc $(DO_CXX) ${B}/src/%.o: src/%.cc $(DO_CXX) ${B}/qtui/%.base.h: src/qtui/%.ui $(DO_UIC) ${B}/implui/%.moc.cc: src/implui/%.h $(DO_MOC) ${B}/tools/%.moc.cc: src/tools/%.h $(DO_MOC) ${B}/depui/%.moc.cc: src/depui/%.h $(DO_MOC) ${B}/i18n/%.qm: i18n/%.ts $(DO_LRELEASE) clean: $(Q)rm -f ${LIB_OBJ} $(Q)rm -f ${MM3D_UI} $(Q)rm -f ${MM3D_MOC} $(Q)rm -f ${QMFILES} $(Q)rm -f ${MM3D_OBJ} $(Q)rm -f ${MM3D_MOC_OBJ} $(Q)rm -f $(BIN)/mm3d${BINEXT} mm3d-master/NEWS000066400000000000000000000005231324021725400137060ustar00rootroot00000000000000This is not the NEWS you're looking for. See README for general information See INSTALL for installation instructions See INSTALL.WIN32 for build and install instructions for Windows See COPYING for license (GPL) See ChangeLog for a list of changes since the last version See AUTHORS to find out who is to blame for this software mm3d-master/README000066400000000000000000000035231324021725400140720ustar00rootroot00000000000000This is the README file for Misfit Model 3D (clover.moe fork) Misfit Model 3D is a 3D model editor. It was written and tested on Linux. It is reported to run on other Unix-like operating systems. It also runs on Windows. See INSTALL.WIN32 for Windows-specific instructions. This is an unofficial fork maintained by Zack Middleton (zturtleman). The home page is here: https://clover.moe/mm3d The discussion forum is here: https://forum.clover.moe The original project's home page is here: http://www.misfitcode.com/misfitmodel3d/ The original project's help and developer mailing lists (including archives) are here: http://www.misfitcode.com/misfitmodel3d/mailinglist.html Misfit Model 3D requires Qt (5.x) with OpenGL support. See the INSTALL file for details on where to get these packages. This program uses autoconf and automake for building from source. What this means is that if you are lucky you can install this program with these easy steps: ./autosetup.sh ./configure make sudo make install This will build a 'mm3d' executable and install it in /usr/local/bin. Documentation will be in /usr/local/share/doc/mm3d. On macOS 10.11+, install homebrew from http://brew.sh and run the following commands. brew install autoconf automake qt cpan App::cpanminus # choose sudo in the interactive command cpanm HTML::Template --sudo ./autosetup.sh CXX='clang++ -std=c++11 -stdlib=libc++' ./configure --with-Qt-dir=/usr/local/Cellar/qt/5.10.0_1 --with-macosx-version-min=10.10 make make mm3d.app This will build a 'Misfit Model 3D.app' AppBundle. (macosx-version-min is copied from /usr/local/Cellar/qt/5.10.0_1/mkspecs/macx-clang/qmake.conf) For more detailed installation instructions, see the INSTALL file. See INSTALL.WIN32 for Windows-specific instructions. mm3d-master/README.SVN000066400000000000000000000036441324021725400145430ustar00rootroot00000000000000If you're seeing this file it is probably because you used Subversion to get the source code for this program. If that is the case you may be wondering how to build it (since there isn't a ./configure script to run). The ./configure script and many other files are output files from an early stage of the build process. Those output files are not included in source control, you must build them from the sources. Additionally the translation files and help pages are also output files from the build process. You can build mm3d without building the i18n and doc/html files. For instructions on creating the build files for MM3D, i18n, and help, continue reading below. If you plan to look at or modify the code itself, read the CODE file in this directory may be helpful. To build MM3D: Run the ./autosetup.sh script. This runs autoconf and automake. If those run successfully you will have a ./configure script you can run to start the normal build process. To start the normal build process, see the INSTALL file. If you have problems building the translation files and documentation html files, you can just run "make" from the src/ directory instead of the top level trunk directory. To build i18n translation files: You must have Qt's lrelease program in your path. If this is in your path you should be able to just run "make" in the i18n directory. You do not need to build i18n files to get an mm3d executable. If you get an error that the shell can't find the lrelease program and you don't care about translation files, then you can safely ignore this error. To build doc/html help files: The help files in doc/html are source files that use templates to build the final help pages that appear in the mm3d help window. To build these final html pages you will need to use the hpagemake.pl perl script in the util directory. The perl script requires the HTML::Template perl library to be installed. You can get this library from CPAN. mm3d-master/TODO000066400000000000000000000102121324021725400136730ustar00rootroot00000000000000For 1.4: Test build with gcc 4.3 Finish doc TODO list Update plugin docs to point to User's 1.4 plugin directory ImTex compile fix For 1.6: Resample animation Change animation playback speed Bone Joints Interactive influence weight adjustment IK Considerations Fix relative paths when saving in a different directory Export/Import MM3D Geometry Materials Skeleton Animations Texture Projections Types Icosahedron Gradient textures Only list supported image formats in animation capture export Integrate libmisfit Make middle mouse button scroll zoom in on point under the mouse Delay normal calculation when manipulating a large number of vertices Fix MM3D data size problem (assume size instead of using read size) Embedded textures Implement embedded textures Extract embedded textures to external files Allow double-sided polygons Attract near/far Position decal 2D/3D Curve: linear/sin/log/quad Later: Warn user if some model properties will not be saved in specified format Format options: Model format-specific dialog box (like Save dialog) Must save in that format to get dialog Dialog always available (tabbed for each format?) Save format-specific options in MM3D format Options dialog can encode/decode Prompt at save time Only prompt for options on first save or on "Save As" Meta data context panel For meta data of any primitive Coloring on texture paint Adjust texture coordinates on turn edge? Adjust texture coordinates on split edge? On user path input, always replace backslashes with slashes MD3 Custom export dialog to select groups, tags, and animations Handle missing/out-of-order animations more sanely Center viewport on mouse position Point meta data? Check flipping on 3DS texture coordinates Import heightmap as "terrain" Transformation - scale translation keyframes MM3D Unsupported data Load/save unknown type info UI for unknown type info Cylinder/Sphere Mapping Projection Window Show test pattern Move pole on sphere? Move pole on icosahedron? Bone Joints Multiple root joints Allowing reparenting and re-rooting of bone structure will invalidate keyframe animations have to deal with parents defined after children Allow setting of other OpenGL options? Commands Increase poly count to smooth (see blender?) Text Force save of a specific type Report OpenGL status (supported options) Unified drawing code Consider using glVertexPointer, glInterleavedArrays, or other draw optimization Import/Export .X (DirectX) Lightwave Export 3DS AC3D Wings MD5 ASE Direct primitive property edit Scale UV Normal Tools Align to line Align to plane Select Select Edge Click repeatedly to cycle through faces under the mouse (Ctrl-click?) Sculpt tool (surface that pushes selected vertices) More complete plugin window Allow enabling/disabling of plugins Allow plugin initialization order changes? Apply heightmap to selected faces Attempt to correct bad data in mm3d load, and allow user to attempt to continue Probably never: Finish MenuManager Hooks for add/remove model elements (for plugins) Scripting Make copy of model Script directories grafted into menu Script debugger Selection Select All Created (or all of type) Bilinear autoscale on non-power-of-two textures Animation Add frame relative Tools Ruler Chamfered primitives Custom lighting Save viewport as JPEG Import/Export FBX SMD Gamestudio MDL Renderman Blender Maya ASCII Raw OpenGL (Triangle Vertices, Normals, and Texture Coords) Texture coordinates Map group should preserve aspect ratio mm3d-master/TRANSLATORS000066400000000000000000000000301324021725400147370ustar00rootroot00000000000000Slovak Dusan Halicky mm3d-master/acinclude.m4000066400000000000000000001363451324021725400154140ustar00rootroot00000000000000AC_DEFUN([KSW_IS_PROFILE], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for profile) AC_ARG_ENABLE([profile], [ --enable-profile=yes/no/core Specify "yes" or "core" to enable profiling.]) is_profile=no PROFILE= CORE_PROFILE= if test x"$enable_profile" = xyes; then PROFILE=-pg CORE_PROFILE=-pg is_profile=yes elif test x"$enable_profile" = xcore; then CORE_PROFILE=-pg is_profile="yes (core)" fi AC_DEFINE( [PROFILE], [], [Define to include profiling information] ) AC_DEFINE( [CORE_PROFILE], [], [Define to include core profiling information] ) AC_MSG_RESULT($is_profile) ]) AC_DEFUN([KSW_IS_DEBUG], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for debug) AC_ARG_ENABLE([debug], [ --enable-debug=yes/no/cov Specify "yes" to enable a debug build.]) is_debug=no enable_debug_save_COVFLAGS="${COVFLAGS}" enable_debug_save_COVLFLAGS="${COVLFLAGS}" enable_debug_save_CFLAGS="${CFLAGS}" enable_debug_save_CXXFLAGS="${CXXFLAGS}" enable_debug_save_LDFLAGS="${LDFLAGS}" if test x"$enable_debug" = xyes; then COVFLAGS="" COVLFLAGS="" CFLAGS="-g -fPIC" CXXFLAGS="${CFLAGS}" LDFLAGS="" elif test x"$enable_debug" = xcov; then COVFLAGS="-coverage" COVLFLAGS="-lgcov" CFLAGS="-g -fPIC" CXXFLAGS="${CFLAGS}" LDFLAGS="" is_debug=coverage else omit_frame= # FIXME?: Using -fomit-frame-pointer causes SEGFAULT at start up on macOS 10.11 using clang++. #if test x"${CORE_PROFILE}" = "x"; then # omit_frame="-fomit-frame-pointer" #fi COVFLAGS="" COVLFLAGS="" CFLAGS="-O2 ${omit_frame} -fno-math-errno -fPIC" CXXFLAGS="${CFLAGS}" LDFLAGS="${omit_frame} -fno-math-errno" fi AC_TRY_LINK([#include ], , [ dnl Yay! if test x"$enable_debug" = xyes; then AC_DEFINE( [CODE_DEBUG], [], [Define to include debugging information] ) is_debug=yes fi ], [ dnl Boo! if test x"$enable_debug" != xyes; then COVFLAGS="${enable_debug_save_COVFLAGS}" COVLFLAGS="${enable_debug_save_COVLFLAGS}" CFLAGS="${enable_debug_save_CFLAGS}" CXXFLAGS="${enable_debug_save_CXXFLAGS}" LDFLAGS="${enable_debug_save_LDFLAGS}" AC_DEFINE( [CODE_DEBUG], [], [Define to include debugging information] ) is_debug=yes else COVFLAGS="${enable_debug_save_COVFLAGS}" COVLFLAGS="${enable_debug_save_COVLFLAGS}" CFLAGS="${enable_debug_save_CFLAGS}" CXXFLAGS="${enable_debug_save_CXXFLAGS}" LDFLAGS="${enable_debug_save_LDFLAGS}" fi ]) AC_SUBST(COVFLAGS) AC_SUBST(COVLFLAGS) AC_MSG_RESULT($is_debug) ]) dnl for lua (KSW was here) AC_DEFUN([KSW_HAVE_LUA], [ AC_REQUIRE([AC_PROG_CC]) AC_MSG_CHECKING(for lua) AC_ARG_WITH([lua-dir], [ --with-lua-dir=DIR DIR is equal to the install prefix of Lua. Header files are in DIR/include, and Library files are in DIR/lib]) AC_ARG_WITH([lua-include-dir], [ --with-lua-include-dir=DIR Lua header files are in DIR]) AC_ARG_WITH([lua-lib-dir], [ --with-lua-lib-dir=DIR Lua libraries are in DIR]) AC_ARG_WITH([lua-lib], [ --with-lua-lib=LIB Use -lLIB to link with the lua library]) if test x"$with_lua_dir" = x && test x"$with_lua_include_dir" = x && test x"$with_lua_lib_dir" = x && test x"$with_lua_lib" = x; then # user did not request Lua support, disable it have_lua="disabled" else # "yes" is a bogus option if test x"$with_lua_dir" = xyes; then with_lua_dir= fi if test x"$with_lua_include_dir" = xyes; then with_lua_include_dir= fi if test x"$with_lua_lib_dir" = xyes; then with_lua_lib_dir= fi if test x"$with_lua_lib" = xyes; then with_lua_lib= fi # No lua unless we discover otherwise have_lua=no # Check whether we are requested to link with a specific version if test x"$with_lua_lib" != x; then ksw_lua_lib="$with_lua_lib" fi # Check whether we were supplied with an answer already if test x"$with_lua_dir" != x; then have_lua=yes ksw_lua_dir="$with_lua_dir" ksw_lua_include_dir="$with_lua_dir/include" if test -d "$with_lua_dir/lib64" ; then ksw_lua_lib_dir="$with_lua_dir/lib64" else ksw_lua_lib_dir="$with_lua_dir/lib" fi # Only search for the lib if the user did not define one already if test x"$ksw_lua_lib" = x; then ksw_lua_lib="`ls $ksw_lua_lib_dir/liblua5* 2> /dev/null | sed -n 1p | sed s@$ksw_lua_lib_dir/lib@@ | [sed s@[.].*@@]`" fi if test x"$ksw_lua_lib" = x; then ksw_lua_lib="`ls $ksw_lua_lib_dir/liblua.* 2> /dev/null | sed -n 1p | sed s@$ksw_lua_lib_dir/lib@@ | [sed s@[.].*@@]`" fi ksw_lua_LIBS="-L$ksw_lua_lib_dir -l$ksw_lua_lib -lm -ldl" else # Use cached value or do search, starting with suggestions from # the command line AC_CACHE_VAL(ksw_cv_have_lua, [ # We are not given a solution and there is no cached value. ksw_lua_dir= if test x"$ksw_lua_include_dir" = x; then ksw_lua_include_dir="`ls -dr /usr/include/lua.h /usr/local/include/lua.h /usr/include/lua*/lua.h /usr/local/include/lua*/lua.h 2> /dev/null | sed -n 1p | sed s@/lua.h@@`" fi if test x"$ksw_lua_lib" = x; then ksw_lua_lib_dir="`ls -dr /usr/lib64/liblua5* /usr/lib64/liblua.* /usr/local/lib64/liblua5* /usr/local/lib64/liblua.* /usr/lib/liblua5* /usr/lib/liblua.* /usr/local/lib/liblua5* /usr/local/lib/liblua.* 2> /dev/null | sed -n 1p`" ksw_lua_lib="`echo $ksw_lua_lib_dir | sed 's@/.*/@@' `" ksw_lua_lib_dir="`echo $ksw_lua_lib_dir | sed s@/$ksw_lua_lib@@ `" ksw_lua_lib="`echo $ksw_lua_lib | [sed s@[.].*@@] | sed s@^lib@@ `" fi if test x"$ksw_lua_lib" != x; then if test x"$ksw_lua_lib_dir" = x; then ksw_lua_LIBS="-l$ksw_lua_lib -lm -ldl" else ksw_lua_LIBS="-L$ksw_lua_lib_dir -l$ksw_lua_lib -lm -ldl" fi # Record where we found lua for the cache. ksw_cv_have_lua="have_lua=yes \ ksw_lua_dir=$ksw_lua_dir \ ksw_lua_include_dir=$ksw_lua_include_dir \ ksw_lua_LIBS=\"$ksw_lua_LIBS\"" fi ])dnl eval "$ksw_cv_have_lua" fi # all $ksw_lua_* are set fi # $have_lua reflects the system status if test x"$have_lua" = xyes; then LUA_CCFLAGS="-I$ksw_lua_include_dir" LUA_DIR="$ksw_lua_dir" LUA_LIBS="$ksw_lua_LIBS" # All variables are defined, report the result AC_DEFINE( [HAVE_LUA], [], [Define when you have Lua installed] ) AC_MSG_RESULT([$have_lua: LUA_CCFLAGS=$LUA_CCFLAGS LUA_DIR=$LUA_DIR LUA_LIBS=$LUA_LIBS ]) else # lua was not found LUA_CCFLAGS= LUA_DIR= LUA_LIBS= AC_MSG_RESULT($have_lua) fi AC_SUBST(LUA_CCFLAGS) AC_SUBST(LUA_DIR) AC_SUBST(LUA_LIBS) #### Being paranoid: if test x"$have_lua" = xyes; then AC_MSG_CHECKING(correct functioning of lua installation) AC_CACHE_VAL(ksw_cv_lua_test_result, [ cat > ksw_lua_test.h << EOF EOF cat > ksw_lua_test.c << EOF #include "ksw_lua_test.h" #include #include //#include int main( int argc, char **argv ) { lua_State * L = lua_open(); //luaopen_math( L ); lua_close( L ); return( 0 ); } EOF ksw_cv_lua_test_result="failure" ksw_try_1="$CC $LUA_CCFLAGS $LUA_LIBS -o ksw_lua_test ksw_lua_test.c >/dev/null 2>ksw_lua_test_1.out" AC_TRY_EVAL(ksw_try_1) ksw_err_1=`grep -v '^ *+' ksw_lua_test_1.out | grep -v "^ksw_lua_test.{$ac_ext}\$"` if test x"$ksw_err_1" != x; then echo "$ksw_err_1" >&AC_FD_CC echo "configure: could not compile:" >&AC_FD_CC cat ksw_lua_test.c >&AC_FD_CC else ksw_cv_lua_test_result="success" fi fi ])dnl AC_CACHE_VAL ksw_cv_lua_test_result AC_MSG_RESULT([$ksw_cv_lua_test_result]); if test x"$ksw_cv_lua_test_result" = "xfailure"; then AC_MSG_ERROR([Failed to find matching components of a complete lua installation. Try using more options, see ./configure --help.]) fi rm -f ksw_lua_test.h \ ksw_lua_test.c ksw_lua_test.o ksw_lua_test \ ksw_lua_test_1.out ]) dnl for lualib (KSW was here) AC_DEFUN([KSW_HAVE_LUALIB], [ if test x"${LUA_LIBS}" != x; then AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([KSW_HAVE_LUA]) AC_MSG_CHECKING(for lualib) AC_ARG_WITH([lualib-dir], [ --with-lualib-dir=DIR DIR is equal to the install prefix of Lualib. Header files are in DIR/include, and Library files are in DIR/lib]) AC_ARG_WITH([lualib-include-dir], [ --with-lualib-include-dir=DIR Lua header files are in DIR]) AC_ARG_WITH([lualib-lib-dir], [ --with-lualib-lib-dir=DIR Lua libraries are in DIR]) AC_ARG_WITH([lualib-lib], [ --with-lualib-lib=LIB Use -lLIB to link with the lualib library]) if test x"$with_lualib_dir" = x"no" || test x"$with_lualib_include_dir" = x"no" || test x"$with_lualib_lib_dir" = x"no" || test x"$with_lualib_lib" = x"no"; then # user disabled lualib. Leave cache alone. have_lualib="User disabled lualib." else # "yes" is a bogus option if test x"$with_lualib_dir" = xyes; then with_lualib_dir= fi if test x"$with_lualib_include_dir" = xyes; then with_lualib_include_dir= fi if test x"$with_lualib_lib_dir" = xyes; then with_lualib_lib_dir= fi if test x"$with_lualib_lib" = xyes; then with_lualib_lib= fi # No lualib unless we discover otherwise have_lualib=no # Check whether we are requested to link with a specific version if test x"$with_lualib_lib" != x; then ksw_lualib_lib="$with_lualib_lib" fi # Check whether we were supplied with an answer already if test x"$with_lualib_dir" != x; then have_lualib=yes ksw_lualib_dir="$with_lualib_dir" ksw_lualib_include_dir="$with_lualib_dir/include" if test -d "$with_lualib_dir/lib64" ; then ksw_lualib_lib_dir="$with_lualib_dir/lib64" else ksw_lualib_lib_dir="$with_lualib_dir/lib" fi # Only search for the lib if the user did not define one already if test x"$ksw_lualib_lib" = x; then ksw_lualib_lib="`ls $ksw_lualib_lib_dir/liblualib5* 2> /dev/null | sed -n 1p | sed s@$ksw_lualib_lib_dir/lib@@ | [sed s@[.].*@@]`" fi if test x"$ksw_lualib_lib" = x; then ksw_lualib_lib="`ls $ksw_lualib_lib_dir/liblualib.* 2> /dev/null | sed -n 1p | sed s@$ksw_lualib_lib_dir/lib@@ | [sed s@[.].*@@]`" fi ksw_lualib_LIBS="-L$ksw_lualib_lib_dir -l$ksw_lualib_lib" else # Use cached value or do search, starting with suggestions from # the command line AC_CACHE_VAL(ksw_cv_have_lualib, [ # We are not given a solution and there is no cached value. ksw_lualib_dir= if test x"$ksw_lualib_include_dir" = x; then ksw_lualib_include_dir="`ls -dr /usr/include/lualib.h /usr/local/include/lualib.h /usr/include/lua*/lualib.h /usr/local/include/lua*/lualib.h 2> /dev/null | sed -n 1p | sed s@/lualib.h@@`" fi if test x"$ksw_lualib_lib" = x; then ksw_lualib_lib_dir="`ls -dr /usr/lib64/liblualib5* /usr/lib64/liblualib.* /usr/local/lib64/liblualib5* /usr/local/lib64/liblualib.* /usr/lib/liblualib5* /usr/lib/liblualib.* /usr/local/lib/liblualib5* /usr/local/lib/liblualib.* 2> /dev/null | sed -n 1p`" ksw_lualib_lib="`echo $ksw_lualib_lib_dir | sed 's@/.*/@@' `" ksw_lualib_lib_dir="`echo $ksw_lualib_lib_dir | sed s@/$ksw_lualib_lib@@ `" ksw_lualib_lib="`echo $ksw_lualib_lib | [sed s@[.].*@@] | sed s@^lib@@ `" fi if test x"$ksw_lualib_lib" != x; then if test x"$ksw_lualib_lib_dir" = x; then ksw_lualib_LIBS="-l$ksw_lualib_lib" else ksw_lualib_LIBS="-L$ksw_lualib_lib_dir -l$ksw_lualib_lib" fi # Record where we found lualib for the cache. ksw_cv_have_lualib="have_lualib=yes \ ksw_lualib_dir=$ksw_lualib_dir \ ksw_lualib_include_dir=$ksw_lualib_include_dir \ ksw_lualib_LIBS=\"$ksw_lualib_LIBS\"" fi ])dnl eval "$ksw_cv_have_lualib" fi # all $ksw_lualib_* are set fi # $have_lualib reflects the system status if test x"$have_lualib" = xyes; then LUALIB_CCFLAGS="-I$ksw_lualib_include_dir" LUALIB_DIR="$ksw_lualib_dir" LUALIB_LIBS="-lm -ldl $LUA_LIBS $ksw_lualib_LIBS" # All variables are defined, report the result AC_DEFINE( [HAVE_LUALIB], [], [Define when you have Lua libs installed] ) AC_MSG_RESULT([$have_lualib: LUALIB_CCFLAGS=$LUALIB_CCFLAGS LUALIB_DIR=$LUALIB_DIR LUALIB_LIBS=$LUALIB_LIBS ]) else # lualib was not found LUALIB_CCFLAGS= LUALIB_DIR= LUALIB_LIBS= AC_MSG_RESULT($have_lualib) fi AC_SUBST(LUALIB_CCFLAGS) AC_SUBST(LUALIB_DIR) AC_SUBST(LUALIB_LIBS) #### Being paranoid: if test x"$have_lualib" = xyes; then AC_MSG_CHECKING(correct functioning of lualib installation) AC_CACHE_VAL(ksw_cv_lualib_test_result, [ cat > ksw_lualib_test.h << EOF EOF cat > ksw_lualib_test.c << EOF #include "ksw_lualib_test.h" #include #include #include int main( int argc, char **argv ) { lua_State * L = lua_open(); luaopen_math( L ); lua_close( L ); return( 0 ); } EOF ksw_cv_lualib_test_result="failure" ksw_try_1="$CC $LUALIB_CCFLAGS $LUALIB_LIBS -o ksw_lualib_test ksw_lualib_test.c >/dev/null 2>ksw_lualib_test_1.out" AC_TRY_EVAL(ksw_try_1) ksw_err_1=`grep -v '^ *+' ksw_lualib_test_1.out | grep -v "^ksw_lualib_test.{$ac_ext}\$"` if test x"$ksw_err_1" != x; then echo "$ksw_err_1" >&AC_FD_CC echo "configure: could not compile:" >&AC_FD_CC cat ksw_lualib_test.c >&AC_FD_CC else ksw_cv_lualib_test_result="success" fi fi ])dnl AC_CACHE_VAL ksw_cv_lualib_test_result AC_MSG_RESULT([$ksw_cv_lualib_test_result]); if test x"$ksw_cv_lualib_test_result" = "xfailure"; then AC_MSG_ERROR([Failed to find matching components of a complete lualib installation. Try using more options, see ./configure --help.]) fi rm -f ksw_lualib_test.h \ ksw_lualib_test.c ksw_lualib_test.o ksw_lualib_test \ ksw_lualib_test_1.out fi ]) dnl for Qt (KSW was here) AC_DEFUN([BNV_HAVE_QT], [ dnl THANKS! This code includes bug fixes by: dnl Tim McClarren. AC_REQUIRE([AC_PROG_CXX]) AC_REQUIRE([AC_PATH_X]) AC_REQUIRE([AC_PATH_XTRA]) AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_MSG_CHECKING(for Qt) dnl Recent QT4 doesn't need these anymore. -- garden@acheronte.it dnl QT_XLIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" QT_XLIBS="" if test x"$no_x" = xyes; then QT_XLIBS="" fi dnl KSW hackish... requires another macro to set is_osx if test x"$is_osx" = xyes; then QT_XLIBS="" fi AC_ARG_WITH([Qt-dir], [ --with-Qt-dir=DIR DIR is equal to \$QTDIR if you have followed the installation instructions of Trolltech. Header files are in DIR/include, binary utilities are in DIR/bin and the library is in DIR/lib]) AC_ARG_WITH([Qt-include-dir], [ --with-Qt-include-dir=DIR Qt header files are in DIR]) AC_ARG_WITH([Qt-bin-dir], [ --with-Qt-bin-dir=DIR Qt utilities such as moc and uic are in DIR]) AC_ARG_WITH([Qt-lib-dir], [ --with-Qt-lib-dir=DIR The Qt library is in DIR]) bnv_is_qt5=no if test x"$is_osx" = xyes; then bnv_qt5_libs="-framework QtCore -framework QtGui -framework QtWidgets -framework QtOpenGL" else bnv_qt5_libs="-lQt5Core -lQt5Gui -lQt5Widgets -lQt5OpenGL" fi if test x"$with_Qt_dir" = x"no" || test x"$with_Qt_include_dir" = x"no" || test x"$with_Qt_bin_dir" = x"no" || test x"$with_Qt_lib_dir" = x"no"; then # user disabled Qt. Leave cache alone. have_qt="User disabled Qt." else # "yes" is a bogus option if test x"$with_Qt_dir" = xyes; then with_Qt_dir= fi if test x"$with_Qt_include_dir" = xyes; then with_Qt_include_dir= fi if test x"$with_Qt_bin_dir" = xyes; then with_Qt_bin_dir= fi if test x"$with_Qt_lib_dir" = xyes; then with_Qt_lib_dir= fi # No Qt unless we discover otherwise have_qt=no # Check whether we were supplied with an answer already if test x"$with_Qt_dir" != x; then have_qt=yes bnv_qt_dir="$with_Qt_dir" bnv_qt_include_dir="$with_Qt_dir/include" bnv_qt_bin_dir="$with_Qt_dir/bin" if test -d "$with_Qt_dir/lib64" ; then bnv_qt_lib_dir="$with_Qt_dir/lib64" else bnv_qt_lib_dir="$with_Qt_dir/lib" fi if test x"$is_osx" = xyes; then bnv_qt_LIBS="-F$bnv_qt_dir/Frameworks -L$bnv_qt_lib_dir $bnv_qt5_libs $QT_XLIBS " else bnv_qt_LIBS="-L$bnv_qt_lib_dir $bnv_qt5_libs $QT_XLIBS " fi else # Use cached value or do search, starting with suggestions from # the command line AC_CACHE_VAL(bnv_cv_have_qt, [ # We are not given a solution and there is no cached value. bnv_qt_dir=NO bnv_qt_include_dir=NO bnv_qt_lib_dir=NO BNV_PATH_QT_DIRECT if test "$bnv_qt_dir" = NO || test "$bnv_qt_include_dir" = NO || test "$bnv_qt_lib_dir" = NO; then # Problem with finding complete Qt. Cache the known absence of Qt. bnv_cv_have_qt="have_qt=no" else # Record where we found Qt for the cache. bnv_cv_have_qt="have_qt=yes \ bnv_qt_dir=$bnv_qt_dir \ bnv_qt_include_dir=$bnv_qt_include_dir \ bnv_qt_bin_dir=$bnv_qt_bin_dir \ bnv_is_qt5=$bnv_is_qt5 \ bnv_qt_LIBS=\"$bnv_qt_LIBS\"" fi ])dnl eval "$bnv_cv_have_qt" fi # all $bnv_qt_* are set fi # $have_qt reflects the system status if test x"$have_qt" = xyes; then QT_CXXFLAGS="-I$bnv_qt_include_dir" QT_DIR="$bnv_qt_dir" QT_LIBS="$bnv_qt_LIBS" if test x"$bnv_qt_bin_dir" != x; then # We were told where to look for the utilities? # UIC detection if test -x "$bnv_qt_bin_dir/uic"; then QT_UIC="$bnv_qt_bin_dir/uic" fi # MOC detection if test -x "$bnv_qt_bin_dir/moc"; then QT_MOC="$bnv_qt_bin_dir/moc" fi # LRELEASE detection if test -x "$bnv_qt_bin_dir/lrelease"; then QT_LRELEASE="$bnv_qt_bin_dir/lrelease" fi # MACDEPLOYQT detection if test -x "$bnv_qt_bin_dir/macdeployqt"; then QT_MACDEPLOYQT="$bnv_qt_bin_dir/macdeployqt" fi elif test x"$bnv_qt_dir" != x; then # If bnv_qt_dir is defined, utilities are expected to be in the # bin subdirectory # UIC detection if test -x "$bnv_qt_dir/bin/uic"; then QT_UIC="$bnv_qt_dir/bin/uic" fi # MOC detection if test -x "$bnv_qt_dir/bin/moc"; then QT_MOC="$bnv_qt_dir/bin/moc" fi # LRELEASE detection if test -x "$bnv_qt_dir/bin/lrelease"; then QT_LRELEASE="$bnv_qt_dir/bin/lrelease" fi # MACDEPLOYQT detection if test -x "$bnv_qt_dir/bin/macdeployqt"; then QT_MACDEPLOYQT="$bnv_qt_dir/bin/macdeployqt" fi fi # If binaries are still not set, try /usr/lib/x86_64-linux-gnu/qt5/bin/ if test x"$host_alias" != x; then # set by configure --host bnv_qt_lib_host=$host_alias else bnv_qt_lib_host=`sh config.guess | cut -d'-' -f 1,3-4` fi if test x"$QT_UIC" = x; then # UIC detection if test -x "/usr/lib/$bnv_qt_lib_host/qt5/bin/uic"; then QT_UIC="/usr/lib/$bnv_qt_lib_host/qt5/bin/uic" fi fi if test x"$QT_MOC" = x; then # MOC detection if test -x "/usr/lib/$bnv_qt_lib_host/qt5/bin/moc"; then QT_MOC="/usr/lib/$bnv_qt_lib_host/qt5/bin/moc" fi fi if test x"$QT_LRELEASE" = x; then # LRELEASE detection if test -x "/usr/lib/$bnv_qt_lib_host/qt5/bin/lrelease"; then QT_LRELEASE="/usr/lib/$bnv_qt_lib_host/qt5/bin/lrelease" fi fi if test x"$QT_MACDEPLOYQT" = x; then # MACDEPLOYQT detection if test -x "/usr/lib/$bnv_qt_lib_host/qt5/bin/macdeployqt"; then QT_MACDEPLOYQT="/usr/lib/$bnv_qt_lib_host/qt5/bin/macdeployqt" fi fi # If binaries are still not set, try qtchooser if test x"$QT_UIC" = x; then # UIC detection if test `which qtchooser 2> /dev/null`; then QT_UIC="qtchooser -qt=5 -run-tool=uic" fi fi if test x"$QT_MOC" = x; then # MOC detection if test `which qtchooser 2> /dev/null`; then QT_MOC="qtchooser -qt=5 -run-tool=moc" fi fi if test x"$QT_LRELEASE" = x; then # LRELEASE detection if test `which qtchooser 2> /dev/null`; then QT_LRELEASE="qtchooser -qt=5 -run-tool=lrelease" fi fi if test x"$QT_MACDEPLOYQT" = x; then # MACDEPLOYQT detection if test `which qtchooser 2> /dev/null`; then QT_MACDEPLOYQT="qtchooser -qt=5 -run-tool=macdeployqt" fi fi # If binaries are still not set, try $PATH if test x"$QT_UIC" = x; then # UIC detection if test `which uic 2> /dev/null`; then QT_UIC=`which uic` fi fi if test x"$QT_MOC" = x; then # MOC detection if test `which moc 2> /dev/null`; then QT_MOC=`which moc` fi fi if test x"$QT_LRELEASE" = x; then # LRELEASE detection if test `which lrelease 2> /dev/null`; then QT_LRELEASE=`which lrelease` fi fi if test x"$QT_MACDEPLOYQT" = x; then # MACDEPLOYQT detection if test `which macdeployqt 2> /dev/null`; then QT_MACDEPLOYQT=`which macdeployqt` fi fi # All variables are defined, report the result AC_MSG_RESULT([$have_qt: QT_CXXFLAGS=$QT_CXXFLAGS QT_DIR=$QT_DIR QT_LIBS=$QT_LIBS QT_UIC=$QT_UIC QT_MOC=$QT_MOC QT_LRELEASE=$QT_LRELEASE QT_MACDEPLOYQT=$QT_MACDEPLOYQT]) else # Qt was not found QT_CXXFLAGS= QT_DIR= QT_LIBS= QT_UIC= QT_MOC= QT_LRELEASE= QT_MACDEPLOYQT= AC_MSG_RESULT($have_qt) fi if test x"$bnv_is_qt5" = xyes; then HAVE_QT5=1 AC_SUBST(HAVE_QT5) AC_DEFINE( [HAVE_QT5], [], [Define when you have QT5 installed] ) fi AC_SUBST(QT_CXXFLAGS) AC_SUBST(QT_DIR) AC_SUBST(QT_LIBS) AC_SUBST(QT_UIC) AC_SUBST(QT_MOC) AC_SUBST(QT_LRELEASE) AC_SUBST(QT_MACDEPLOYQT) #### Being paranoid: if test x"$have_qt" = xyes; then AC_MSG_CHECKING(correct functioning of Qt installation) AC_CACHE_VAL(bnv_cv_qt_test_result, [ cat > bnv_qt_test.h << EOF #include class Test : public QObject { Q_OBJECT public: Test() {} ~Test() {} public slots: void receive() {} signals: void send(); }; EOF cat > bnv_qt_main.$ac_ext << EOF #include "bnv_qt_test.h" #include int main( int argc, char **argv ) { QApplication app( argc, argv ); Test t; QObject::connect( &t, SIGNAL(send()), &t, SLOT(receive()) ); } EOF bnv_cv_qt_test_result="failure" bnv_try_1="$QT_MOC bnv_qt_test.h -o moc_bnv_qt_test.$ac_ext >/dev/null 2>bnv_qt_test_1.out" AC_TRY_EVAL(bnv_try_1) bnv_err_1=`grep -v '^ *+' bnv_qt_test_1.out | grep -v "^bnv_qt_test.h\$"` if test x"$bnv_err_1" != x; then echo "$bnv_err_1" >&AC_FD_CC echo "configure: could not run $QT_MOC on:" >&AC_FD_CC cat bnv_qt_test.h >&AC_FD_CC else bnv_try_2="$CXX $QT_CXXFLAGS -c $CXXFLAGS -Wno-non-virtual-dtor -o moc_bnv_qt_test.o moc_bnv_qt_test.$ac_ext >/dev/null 2>bnv_qt_test_2.out" AC_TRY_EVAL(bnv_try_2) bnv_err_2=`grep -v '^ *+' bnv_qt_test_2.out | grep -v "^bnv_qt_test.{$ac_ext}\$"` if test x"$bnv_err_2" != x; then echo "$bnv_err_2" >&AC_FD_CC echo "configure: could not compile:" >&AC_FD_CC cat bnv_qt_test.$ac_ext >&AC_FD_CC else bnv_try_3="$CXX $QT_CXXFLAGS -c $CXXFLAGS -o bnv_qt_main.o bnv_qt_main.$ac_ext >/dev/null 2>bnv_qt_test_3.out" AC_TRY_EVAL(bnv_try_3) bnv_err_3=`grep -v '^ *+' bnv_qt_test_3.out | grep -v "^bnv_qt_main.{$ac_ext}\$"` if test x"$bnv_err_3" != x; then echo "$bnv_err_3" >&AC_FD_CC echo "configure: could not compile:" >&AC_FD_CC cat bnv_qt_main.$ac_ext >&AC_FD_CC else bnv_try_4="$CXX $LDFLAGS -o bnv_qt_main bnv_qt_main.o moc_bnv_qt_test.o $QT_LIBS $LIBS >/dev/null 2>bnv_qt_test_4.out" AC_TRY_EVAL(bnv_try_4) bnv_err_4=`grep -v '^ *+' bnv_qt_test_4.out` if test x"$bnv_err_4" != x; then echo "$bnv_err_4" >&AC_FD_CC else bnv_cv_qt_test_result="success" fi fi fi fi ])dnl AC_CACHE_VAL bnv_cv_qt_test_result AC_MSG_RESULT([$bnv_cv_qt_test_result]); if test x"$bnv_cv_qt_test_result" = "xfailure"; then AC_MSG_ERROR([Failed to find matching components of a complete Qt installation. Try using more options, see ./configure --help.]) fi rm -f bnv_qt_test.h moc_bnv_qt_test.$ac_ext moc_bnv_qt_test.o \ bnv_qt_main.$ac_ext bnv_qt_main.o bnv_qt_main \ bnv_qt_test_1.out bnv_qt_test_2.out bnv_qt_test_3.out bnv_qt_test_4.out fi AC_LANG_RESTORE ]) dnl Internal subroutine of BNV_HAVE_QT dnl Set bnv_qt_dir bnv_qt_include_dir bnv_qt_bin_dir bnv_qt_lib_dir dnl Copyright 2001 Bastiaan N. Veelo dnl Modified in 2018 by Zack Middleton AC_DEFUN([BNV_PATH_QT_DIRECT], [ if test x"$host_alias" != x; then # set by configure --host bnv_qt_host=$host_alias else bnv_qt_host=`sh config.guess | cut -d'-' -f 1,3-4` fi ## Binary utilities ## if test x"$with_Qt_bin_dir" != x; then bnv_qt_bin_dir=$with_Qt_bin_dir fi ## Look for header files ## if test x"$with_Qt_include_dir" != x; then bnv_qt_include_dir="$with_Qt_include_dir" else # The following header file is expected to define QT_VERSION. # Look for the header file in a standard set of common directories. bnv_include_path_list=" /usr/include/$bnv_qt_host/qt5 /usr/include/qt5 /usr/qt5/include /usr/local/include/$bnv_qt_host/qt5 /usr/local/include/qt5 /usr/local/qt5/include `ls -dr /usr/local/Cellar/qt/5*/include 2>/dev/null` " for bnv_dir in $bnv_include_path_list; do if test -r "$bnv_dir/QtCore/qconfig.h"; then bnv_dirs="$bnv_dirs $bnv_dir" fi done # Now look for the newest in this list bnv_prev_ver=0x04FFFF for bnv_dir in $bnv_dirs; do # Qt 5.7.0 and later use separate defines in qconfig.h if test -r "$bnv_dir/QtCore/qconfig.h"; then ztm_qt_ver_major=`egrep -w '#define QT_VERSION_MAJOR' $bnv_dir/QtCore/qconfig.h | sed s/'#define QT_VERSION_MAJOR'//` if test x"$ztm_qt_ver_major" != x; then ztm_qt_ver_minor=`egrep -w '#define QT_VERSION_MINOR' $bnv_dir/QtCore/qconfig.h | sed s/'#define QT_VERSION_MINOR'//` ztm_qt_ver_patch=`egrep -w '#define QT_VERSION_PATCH' $bnv_dir/QtCore/qconfig.h | sed s/'#define QT_VERSION_PATCH'//` bnv_this_ver=`printf "0x%02X%02X%02X" $ztm_qt_ver_major $ztm_qt_ver_minor $ztm_qt_ver_patch` if expr $bnv_this_ver '>' $bnv_prev_ver > /dev/null; then bnv_is_qt5=yes bnv_qt_include_dir=$bnv_dir bnv_prev_ver=$bnv_this_ver fi # don't check qglobal.h continue fi fi # Before Qt 5.7.0 the version was a constant (i.e., 0x050600 for 5.6.0) in qglobal.h if test -r "$bnv_dir/QtCore/qglobal.h"; then bnv_this_ver=`egrep -w '#define QT_VERSION' $bnv_dir/QtCore/qglobal.h | sed s/'#define QT_VERSION'//` if expr $bnv_this_ver '>' $bnv_prev_ver > /dev/null; then bnv_is_qt5=yes bnv_qt_include_dir=$bnv_dir bnv_prev_ver=$bnv_this_ver fi fi done fi dnl Found header files. # Are these headers located in a traditional Trolltech installation? # That would be $bnv_qt_include_dir stripped from its last element: bnv_found_traditional=no bnv_possible_qt_dir=`dirname $bnv_qt_include_dir` if test -x $bnv_possible_qt_dir/bin/moc; then if ls $bnv_possible_qt_dir/lib/libQt5Core.* 1> /dev/null 2> /dev/null; then bnv_found_traditional=yes elif test -r $bnv_possible_qt_dir/Frameworks/QtCore.framework; then bnv_found_traditional=yes fi fi if test x"$bnv_found_traditional" = xyes; then # Then the rest is a piece of cake bnv_qt_dir=$bnv_possible_qt_dir bnv_qt_bin_dir="$bnv_qt_dir/bin" if test -d "$bnv_qt_dir/lib64" ; then bnv_qt_lib_dir="$bnv_qt_dir/lib64" else bnv_qt_lib_dir="$bnv_qt_dir/lib" fi if test x"$is_osx" = xyes; then bnv_qt_LIBS="-F$bnv_qt_dir/Frameworks -L$bnv_qt_lib_dir $bnv_qt5_libs $QT_XLIBS" else bnv_qt_LIBS="-L$bnv_qt_lib_dir $bnv_qt5_libs $QT_XLIBS" fi fi if test $bnv_found_traditional = no; then # There is no valid definition for $QTDIR as Trolltech likes to see it bnv_qt_dir= ## Look for Qt library ## if test x"$with_Qt_lib_dir" != x; then bnv_qt_lib_dir="$with_Qt_lib_dir" bnv_qt_LIBS="-L$bnv_qt_lib_dir $bnv_qt5_libs $QT_XLIBS" else # Normally, when there is no traditional Trolltech installation, # the library is installed in a place where the linker finds it # automatically. qt_direct_test_header=QtWidgets/QApplication qt_direct_test_main=" int argc; char ** argv; QApplication app(argc,argv); " # See if we find the library without any special options. # Don't add top $LIBS permanently yet bnv_save_LIBS="$LIBS" bnv_save_CXXFLAGS="$CXXFLAGS" CXXFLAGS="-I$bnv_qt_include_dir -fPIC" LIBS="$bnv_qt5_libs $QT_XLIBS" bnv_qt_LIBS="$LIBS" AC_TRY_LINK([#include <$qt_direct_test_header>], $qt_direct_test_main, [ # Succes. # We can link with no special library directory. bnv_qt_lib_dir= ], [ # That did not work. Maybe a library version I don't know about? # Look for some Qt lib in a standard set of common directories. bnv_dir_list=" `echo $bnv_qt_include_dir | sed "s|/include|/lib|"` /usr/lib/$bnv_qt_host /usr/lib/qt5 /usr/qt5/lib /usr/lib64 /usr/lib /usr/local/lib/$bnv_qt_host /usr/local/lib/qt5 /usr/local/qt5/lib /usr/local/lib64 /usr/local/lib /lib64 /lib /opt/lib64 /opt/lib " for bnv_dir in $bnv_dir_list; do if ls $bnv_dir/libQt5Core* > /dev/null 2> /dev/null ; then bnv_qt_lib_dir="$bnv_dir" break fi done # Try with that one LIBS="$bnv_qt5_libs $QT_XLIBS" ]) if test x"$bnv_qt_lib_dir" != x; then bnv_qt_LIBS="-L$bnv_qt_lib_dir $LIBS" else bnv_qt_LIBS="$LIBS" fi LIBS="$bnv_save_LIBS" CXXFLAGS="$bnv_save_CXXFLAGS" fi dnl $with_Qt_lib_dir was not given fi dnl Done setting up for non-traditional Trolltech installation ]) dnl for -lqglviewer (KSW was here) AC_DEFUN([KSW_HAVE_QGL], [ AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([BNV_HAVE_QT]) AC_LANG_SAVE AC_LANG_CPLUSPLUS AC_MSG_CHECKING(Qt OpenGL) AC_CACHE_VAL(ksw_cv_qgl_test_result, [ cat > ksw_qgl_test.${ac_ext} << EOF #include #include #include int main( int argc, char ** argv ) { QApplication app( argc, argv ); QGLWidget w; w.show(); return app.exec(); } EOF ksw_cv_qgl_test_result="failure" ksw_try_1="$CXX $QT_CXXFLAGS $CXXFLAGS $GL_CFLAGS -Wno-uninitialized -o ksw_qgl_test ksw_qgl_test.${ac_ext} $QT_LIBS $GL_LIBS >/dev/null 2>ksw_qgl_test_1.out" AC_TRY_EVAL(ksw_try_1) ksw_err_1=`grep -v '^ *+' ksw_qgl_test_1.out | grep -v "^ksw_qgl_test.{$ac_ext}\$"` if test x"$ksw_err_1" != x; then ksw_try_2="$CXX $QT_CXXFLAGS $CXXFLAGS $GL_CFLAGS -Wno-uninitialized -o ksw_qgl_test ksw_qgl_test.${ac_ext} $QT_LIBS -lqglviewer $GL_LIBS >/dev/null 2>ksw_qgl_test_2.out" AC_TRY_EVAL(ksw_try_2) ksw_err_2=`grep -v '^ *+' ksw_qgl_test_2.out | grep -v "^ksw_qgl_test.{$ac_ext}\$"` if test x"$ksw_err_2" != x; then echo "$ksw_err_2" >&AC_FD_CC echo "configure: could not compile:" >&AC_FD_CC cat ksw_qgl_test.${ac_ext} >&AC_FD_CC else ksw_cv_qgl_test_result="success" QGL_LIBS=-lqglviewer fi else ksw_cv_qgl_test_result="success" QGL_LIBS= fi ])dnl AC_CACHE_VAL ksw_cv_qgl_test_result AC_MSG_RESULT([$ksw_cv_qgl_test_result]); if test x"$ksw_cv_qgl_test_result" = "xfailure"; then AC_MSG_ERROR([Failed to link Qt with OpenGL support.]) fi rm -f ksw_qgl_test.h \ ksw_qgl_test.${ac_ext} ksw_qgl_test.o ksw_qgl_test \ ksw_qgl_test_1.out ksw_qgl_test_2.out AC_SUBST(QGL_LIBS) AC_LANG_RESTORE ]) AC_DEFUN([MDL_HAVE_OPENGL], [ AC_REQUIRE([AC_PROG_CC]) AC_REQUIRE([AC_PATH_X]) AC_REQUIRE([AC_PATH_XTRA]) AC_CACHE_CHECK([for OpenGL], mdl_cv_have_OpenGL, [ dnl Check for Mesa first, unless we were asked not to. AC_ARG_WITH([--with-Mesa], [Prefer the Mesa library over a vendors native OpenGL library (default=yes)], with_Mesa_help_string) AC_ARG_ENABLE(Mesa, $with_Mesa_help_string, use_Mesa=$enableval, use_Mesa=yes) if test x"$use_Mesa" = xyes; then GL_search_list="MesaGL GL" GLU_search_list="MesaGLU GLU" GLX_search_list="MesaGLX GLX" else GL_search_list="GL MesaGL" GLU_search_list="GLU MesaGLU" GLX_search_list="GLX MesaGLX" fi AC_LANG_SAVE AC_LANG_C if test x"$is_osx" = xyes; then GL_CFLAGS="-framework OpenGL -framework AGL" GL_LIBS="-framework OpenGL -framework AGL" else dnl If we are running under X11 then add in the appropriate libraries. if test x"$no_x" != xyes; then dnl Add everything we need to compile and link X programs to GL_X_CFLAGS dnl and GL_X_LIBS. GL_CFLAGS="$X_CFLAGS" dnl Recent QT4 doesn't need these anymore. -- garden@acheronte.it dnl GL_X_LIBS="$X_PRE_LIBS $X_LIBS -lX11 -lXext -lXmu -lXt -lXi $X_EXTRA_LIBS" GL_X_LIBS="" fi fi GL_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$GL_CFLAGS" GL_save_LIBS="$LIBS" LIBS="$GL_X_LIBS" # Save the "AC_MSG_RESULT file descriptor" to FD 8. exec 8>&AC_FD_MSG # Temporarily turn off AC_MSG_RESULT so that the user gets pretty # messages. exec AC_FD_MSG>/dev/null AC_SEARCH_LIBS(glAccum, $GL_search_list, have_GL=yes, have_GL=no) AC_SEARCH_LIBS(gluBeginCurve, $GLU_search_list, have_GLU=yes, have_GLU=no) AC_SEARCH_LIBS(glXChooseVisual, $GLX_search_list, have_GLX=yes, have_GLX=no) AC_SEARCH_LIBS(glutInit, glut, have_glut=yes, have_glut=no) # Restore pretty messages. exec AC_FD_MSG>&8 if test -n "$LIBS"; then mdl_cv_have_OpenGL=yes GL_LIBS="$LIBS" AC_SUBST(GL_CFLAGS) AC_SUBST(GL_LIBS) else mdl_cv_have_OpenGL=no GL_CFLAGS= fi dnl Reset GL_X_LIBS regardless, since it was just a temporary variable dnl and we don't want to be global namespace polluters. GL_X_LIBS= LIBS="$GL_save_LIBS" CPPFLAGS="$GL_save_CPPFLAGS" AC_LANG_RESTORE dnl bugfix: dont forget to cache this variables, too mdl_cv_GL_CFLAGS="$GL_CFLAGS" mdl_cv_GL_LIBS="$GL_LIBS" mdl_cv_have_GL="$have_GL" mdl_cv_have_GLU="$have_GLU" mdl_cv_have_GLX="$have_GLX" mdl_cv_have_glut="$have_glut" ]) GL_CFLAGS="$mdl_cv_GL_CFLAGS" GL_LIBS="$mdl_cv_GL_LIBS" have_GL="$mdl_cv_have_GL" have_GLU="$mdl_cv_have_GLU" have_GLX="$mdl_cv_have_GLX" have_glut="$mdl_cv_have_glut" ]) dnl endof bugfix -ainan AC_DEFUN([KSW_HAVE_DLOPEN], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for dlopen], ksw_cv_have_dlopen, [ DLOPEN_save_LIBS="$LIBS" DLOPEN_LIBS="-ldl -rdynamic" LIBS="$DLOPEN_save_LIBS $DLOPEN_LIBS" cat > ksw_dlopen_test.c << EOF #include #include int main( int argc, char ** argv ) { dlopen( "filename", 0 ); return 0; } EOF if ${CC} -o ksw_dlopen_test ksw_dlopen_test.c $LIBS 2> /dev/null > /dev/null; then have_dlopen=yes else DLOPEN_LIBS="-ldl -Wl,-export-dynamic" LIBS="$DLOPEN_save_LIBS $DLOPEN_LIBS" if ${CC} -o ksw_dlopen_test ksw_dlopen_test.c $LIBS 2> /dev/null > /dev/null; then have_dlopen=yes else DLOPEN_LIBS="-ldl" LIBS="$DLOPEN_save_LIBS $DLOPEN_LIBS" if ${CC} -o ksw_dlopen_test ksw_dlopen_test.c $LIBS 2> /dev/null > /dev/null; then have_dlopen=yes else have_dlopen=no DLOPEN_LIBS= fi fi fi rm -f ksw_dlopen_test ksw_dlopen_test.c LIBS="$DLOPEN_save_LIBS" ksw_cv_DLOPEN_LIBS="$DLOPEN_LIBS" ksw_cv_have_dlopen="$have_dlopen" ]) DLOPEN_LIBS="$ksw_cv_DLOPEN_LIBS" have_dlopen="$ksw_cv_have_dlopen" AC_SUBST(DLOPEN_LIBS) if test x"$have_dlopen" = "xyes"; then AC_DEFINE( [HAVE_DLOPEN], [], [Define when you have dlopen function] ) fi ]) AC_DEFUN([VL_PROG_CC_WARNINGS], [ ansi=$1 if test -z "$ansi"; then msg="for C compiler warning flags" else msg="for C compiler warning and ANSI conformance flags" fi AC_CACHE_CHECK($msg, vl_cv_prog_cc_warnings, [ if test -n "$CC"; then cat > conftest.c <&1 | grep -i "WorkShop" > /dev/null 2>&1 && $CC -c -v -Xc conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-v" else vl_cv_prog_cc_warnings="-v -Xc" fi dnl Digital Unix C compiler elif $CC -V 2>&1 | grep -i "Digital UNIX Compiler" > /dev/null 2>&1 && $CC -c -verbose -w0 -warnprotos -std1 conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos" else vl_cv_prog_cc_warnings="-verbose -w0 -warnprotos -std1" fi dnl C for AIX Compiler elif $CC 2>&1 | grep -i "C for AIX Compiler" > /dev/null 2>&1 && $CC -c -qlanglvl=ansi -qinfo=all conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" else vl_cv_prog_cc_warnings="-qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd -qlanglvl=ansi" fi dnl IRIX C compiler elif $CC -version 2>&1 | grep -i "MIPSpro Compilers" > /dev/null 2>&1 && $CC -c -fullwarn -ansi -ansiE conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-fullwarn" else vl_cv_prog_cc_warnings="-fullwarn -ansi -ansiE" fi dnl HP-UX C compiler elif what $CC 2>&1 | grep -i "HP C Compiler" > /dev/null 2>&1 && $CC -c -Aa +w1 conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="+w1" else vl_cv_prog_cc_warnings="+w1 -Aa" fi dnl The NEC SX-5 (Super-UX 10) C compiler elif $CC -V 2>&1 | grep "/SX" > /dev/null 2>&1 && $CC -c -pvctl[,]fullmsg -Xc conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-pvctl[,]fullmsg" else vl_cv_prog_cc_warnings="-pvctl[,]fullmsg -Xc" fi dnl The Cray C compiler (Unicos) elif $CC -V 2>&1 | grep -i "Cray" > /dev/null 2>&1 && $CC -c -h msglevel 2 conftest.c > /dev/null 2>&1 && test -f conftest.o; then if test -z "$ansi"; then vl_cv_prog_cc_warnings="-h msglevel 2" else vl_cv_prog_cc_warnings="-h msglevel 2 -h conform" fi fi rm -f conftest.* fi if test -n "$vl_cv_prog_cc_warnings"; then CFLAGS="$CFLAGS $vl_cv_prog_cc_warnings" CXXFLAGS="$CXXFLAGS $vl_cv_prog_cc_warnings" else vl_cv_prog_cc_warnings="unknown" fi ]) ])dnl AC_DEFUN([AC_C_BIGENDIAN_CROSS], [AC_CACHE_CHECK(whether byte ordering is bigendian, ac_cv_c_bigendian, [ac_cv_c_bigendian=unknown # See if sys/param.h defines the BYTE_ORDER macro. AC_TRY_COMPILE([#include #include ], [ #if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN bogus endian macros #endif], [# It does; now see whether it defined to BIG_ENDIAN or not. AC_TRY_COMPILE([#include #include ], [ #if BYTE_ORDER != BIG_ENDIAN not big endian #endif], ac_cv_c_bigendian=yes, ac_cv_c_bigendian=no)]) if test $ac_cv_c_bigendian = unknown; then AC_TRY_RUN([main () { /* Are we little or big endian? From Harbison&Steele. */ union { long l; char c[sizeof (long)]; } u; u.l = 1; exit (u.c[sizeof (long) - 1] == 1); }], ac_cv_c_bigendian=no, ac_cv_c_bigendian=yes, [ echo $ac_n "cross-compiling... " 2>&AC_FD_MSG ]) fi]) if test $ac_cv_c_bigendian = unknown; then AC_MSG_CHECKING(to probe for byte ordering) [ cat >conftest.c <&AC_FD_MSG ac_cv_c_bigendian=yes fi if test `grep -l LiTTleEnDian conftest.o` ; then echo $ac_n ' little endian probe OK, ' 1>&AC_FD_MSG if test $ac_cv_c_bigendian = yes ; then ac_cv_c_bigendian=unknown; else ac_cv_c_bigendian=no fi fi echo $ac_n 'guessing bigendian ... ' >&AC_FD_MSG fi fi AC_MSG_RESULT($ac_cv_c_bigendian) fi if test $ac_cv_c_bigendian = yes; then AC_DEFINE(WORDS_BIGENDIAN, 1, [whether byteorder is bigendian]) BYTEORDER=4321 else BYTEORDER=1234 fi AC_DEFINE_UNQUOTED(BYTEORDER, $BYTEORDER, [1234 = LIL_ENDIAN, 4321 = BIGENDIAN]) if test $ac_cv_c_bigendian = unknown; then AC_MSG_ERROR(unknown endianess - sorry, please pre-set ac_cv_c_bigendian) fi ]) AC_DEFUN([KSW_HAVE_X11FONT], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for x11 fonts], ksw_cv_have_x11font, [ cat > ksw_have_x11font_test.c << EOF #include #include int main( int argc, char * argv[] ) { glXUseXFont( 0, 0, 0, 0 ); return 0; } EOF if ${CC} -c ksw_have_x11font_test.c 2> /dev/null > /dev/null; then have_x11font=yes else have_x11font=no fi rm -f ksw_have_x11font* ksw_cv_have_x11font="$have_x11font" ]) have_x11font="$ksw_cv_have_x11font" if test x"$have_x11font" = "xyes"; then AC_DEFINE( [HAVE_XFONT], [], [Define when you have xfont] ) fi ]) AC_DEFUN([KSW_HAVE_GETTIMEOFDAY], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for gettimeofday], ksw_cv_have_gettimeofday, [ cat > ksw_have_gettimeofday_test.c << EOF #include #include int main( int argc, char * argv[] ) { struct timeval tv; gettimeofday( &tv, NULL ); return 0; } EOF if ${CC} -c ksw_have_gettimeofday_test.c 2> /dev/null > /dev/null; then have_gettimeofday=yes else have_gettimeofday=no fi rm -f ksw_have_gettimeofday* ksw_cv_have_gettimeofday="$have_gettimeofday" ]) have_gettimeofday="$ksw_cv_have_gettimeofday" if test x"$have_gettimeofday" = "xyes"; then AC_DEFINE( [HAVE_GETTIMEOFDAY], [], [Define when you have gettimeofday function] ) fi ]) AC_DEFUN([KSW_IS_OSX], [ AC_REQUIRE([AC_PROG_CC]) AC_CACHE_CHECK([for OS X], ksw_cv_is_osx, [ if test -e /System/Library/Frameworks/Carbon.framework; then is_osx=yes else is_osx=no fi rm -f ksw_is_osx* ksw_cv_is_osx="$is_osx" ]) is_osx="$ksw_cv_is_osx" if test x"$is_osx" = "xyes"; then AC_DEFINE( [IS_OSX], [], [Define when you run on OSX] ) fi ]) AC_DEFUN([ZTM_WITH_MACOSX_VERSION_MIN], [ AC_REQUIRE([AC_PROG_CC]) AC_ARG_WITH([macosx-version-min], [ --with-macosx-version-min=VERSION Minimum Mac OS X deployment VERISON (i.e., 10.10), It should not be lower than Qt's macosx-version-min.]) if test x"$with_macosx_version_min" != x; then ztm_macosx_major=`echo $with_macosx_version_min | cut -d. -f1` ztm_macosx_minor=`echo $with_macosx_version_min | cut -d. -f2` if test $ztm_macosx_minor -gt 9; then # Do math and then remove decimal. 10.10 -> 101000.0 -> 101000 MAC_OS_X_VERSION_MIN_REQUIRED=`echo "$ztm_macosx_major * 10000 + $ztm_macosx_minor * 100" | bc` # | cut -d. -f1 else # Multiply by 100 and then remove decimal. 10.7 -> 1070.0 -> 1070 MAC_OS_X_VERSION_MIN_REQUIRED=`echo "$with_macosx_version_min * 100" | bc` # | cut -d. -f1 fi LDFLAGS="$LDFLAGS -mmacosx-version-min=$with_macosx_version_min" CFLAGS="$CFLAGS -mmacosx-version-min=$with_macosx_version_min -DMAC_OS_X_VERSION_MIN_REQUIRED=$MAC_OS_X_VERSION_MIN_REQUIRED" CXXFLAGS="$CXXFLAGS -mmacosx-version-min=$with_macosx_version_min -DMAC_OS_X_VERSION_MIN_REQUIRED=$MAC_OS_X_VERSION_MIN_REQUIRED" MACOSX_DEPLOYMENT_TARGET=$with_macosx_version_min AC_SUBST(MACOSX_DEPLOYMENT_TARGET) fi ]) mm3d-master/autosetup.sh000077500000000000000000000002661324021725400156030ustar00rootroot00000000000000#!/bin/sh # Using autoconf 2.50 and automake 1.9 # If you are trying this with any other version it may not work aclocal && autoconf && automake --add-missing && touch config.h.in mm3d-master/cleanup.sh000077500000000000000000000001051324021725400151710ustar00rootroot00000000000000#!/bin/sh rm `find . -iname "*.base.*"` rm `find . -iname "*.moc.*"` mm3d-master/config.guess000077500000000000000000001262601324021725400155360ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2006-07-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # The plan is that this can be called by configure scripts if you # don't specify an explicit build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; i*:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; x86:Interix*:[3456]*) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T:Interix*:[3456]*) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mm3d-master/config.h.generic000066400000000000000000000004561324021725400162450ustar00rootroot00000000000000#define PACKAGE "mm3d" #define BYTEORDER 1234 #define HAVE_QT5 1 #ifndef WIN32 /* Define when you have dlopen function */ #define HAVE_DLOPEN /* Define when you have gettimeofday function */ #define HAVE_GETTIMEOFDAY /* Define when you have Lua libs installed */ /* #define HAVE_LUALIB */ #endif mm3d-master/config.h.in000066400000000000000000000202751324021725400152400ustar00rootroot00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if the `closedir' function returns void instead of `int'. */ #undef CLOSEDIR_VOID /* Define to include debugging information */ #undef CODE_DEBUG /* Define to include core profiling information */ #undef CORE_PROFILE /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_DIRENT_H /* Define when you have dlopen function */ #undef HAVE_DLOPEN /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ #undef HAVE_DOPRNT /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `ftime' function. */ #undef HAVE_FTIME /* Define to 1 if you have the `getcwd' function. */ #undef HAVE_GETCWD /* Define when you have gettimeofday function */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if you have the `localtime_r' function. */ #undef HAVE_LOCALTIME_R /* Define to 1 if `lstat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_LSTAT_EMPTY_STRING_BUG /* Define when you have Lua installed */ #undef HAVE_LUA /* Define when you have Lua libs installed */ #undef HAVE_LUALIB /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the `mkdir' function. */ #undef HAVE_MKDIR /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H /* Define to 1 if you have the `pow' function. */ #undef HAVE_POW /* Define when you have QT5 installed */ #undef HAVE_QT5 /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 if you have the `realpath' function. */ #undef HAVE_REALPATH /* Define to 1 if you have the `sqrt' function. */ #undef HAVE_SQRT /* Define to 1 if `stat' has the bug that it succeeds when given the zero-length file name argument. */ #undef HAVE_STAT_EMPTY_STRING_BUG /* Define to 1 if stdbool.h conforms to C99. */ #undef HAVE_STDBOOL_H /* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strcasecmp' function. */ #undef HAVE_STRCASECMP /* Define to 1 if you have the `strchr' function. */ #undef HAVE_STRCHR /* Define to 1 if you have the `strcspn' function. */ #undef HAVE_STRCSPN /* Define to 1 if you have the `strdup' function. */ #undef HAVE_STRDUP /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `strncasecmp' function. */ #undef HAVE_STRNCASECMP /* Define to 1 if you have the `strrchr' function. */ #undef HAVE_STRRCHR /* Define to 1 if you have the `strspn' function. */ #undef HAVE_STRSPN /* Define to 1 if you have the `strstr' function. */ #undef HAVE_STRSTR /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_DIR_H /* Define to 1 if you have the header file, and it defines `DIR'. */ #undef HAVE_SYS_NDIR_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIMEB_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have that is POSIX.1 compatible. */ #undef HAVE_SYS_WAIT_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if you have the `vprintf' function. */ #undef HAVE_VPRINTF /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Define when you have xfont */ #undef HAVE_XFONT /* Define to 1 if the system has the type `_Bool'. */ #undef HAVE__BOOL /* Define when you run on OSX */ #undef IS_OSX /* Define to 1 if `lstat' dereferences a symlink specified with a trailing slash. */ #undef LSTAT_FOLLOWS_SLASHED_SYMLINK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define installation prefix */ #undef PREFIX /* Define to include profiling information */ #undef PROFILE /* Define as the return type of signal handlers (`int' or `void'). */ #undef RETSIGTYPE /* Define to 1 if the `S_IS*' macros in do not work properly. */ #undef STAT_MACROS_BROKEN /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME /* Define to 1 if your declares `struct tm'. */ #undef TM_IN_SYS_TIME /* Version number of package */ #undef VERSION /* Define to 1 if the X Window System is missing or not being used. */ #undef X_DISPLAY_MISSING /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to empty if `const' does not conform to ANSI C. */ #undef const /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef int16_t /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to the type of a signed integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef int8_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef mode_t /* Define to `int' if does not define. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to the type of an unsigned integer type of width exactly 16 bits if such a type exists and the standard includes do not define it. */ #undef uint16_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as `fork' if `vfork' does not work. */ #undef vfork mm3d-master/config.sub000077500000000000000000000774601324021725400152100ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2006-09-20' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc) basic_machine=powerpc-unknown ;; ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 # This also exists in the configure program, but was not the # default. # os=-sunos4 ;; m68*-cisco) os=-aout ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: mm3d-master/configure.ac000066400000000000000000000060311324021725400154750ustar00rootroot00000000000000AC_PREREQ(2.61) dnl if you change version, also change src/mm3dcore/version.h, config.h.generic, dnl mm3d-win32-installer.nsi, and src/plugins/Makefile.am AC_INIT(mm3d, 1.3.9, zturtleman@gmail.com) AM_INIT_AUTOMAKE( mm3d, 1.3.9 ) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) # Checks for programs. AC_PROG_CXX AC_PROG_CC AC_PROG_RANLIB KSW_IS_PROFILE KSW_IS_DEBUG ZTM_WITH_MACOSX_VERSION_MIN # Checks for libraries. # Checks for header files. AC_HEADER_DIRENT AC_HEADER_STDC AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([limits.h netinet/in.h stddef.h stdint.h stdlib.h string.h sys/time.h sys/timeb.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_HEADER_STAT AC_HEADER_STDBOOL AC_C_CONST AC_C_INLINE AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT8_T AC_TYPE_MODE_T AC_TYPE_SIZE_T AC_HEADER_TIME AC_STRUCT_TM AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_CLOSEDIR_VOID AC_FUNC_ERROR_AT_LINE AC_FUNC_FORK AC_FUNC_LSTAT AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_FUNC_REALLOC AC_TYPE_SIGNAL AC_FUNC_STAT AC_FUNC_VPRINTF AC_CHECK_FUNCS([ftime getcwd gettimeofday localtime_r memmove memset mkdir pow realpath sqrt strcasecmp strchr strcspn strdup strerror strncasecmp strrchr strspn strstr]) KSW_HAVE_LUA KSW_HAVE_LUALIB KSW_IS_OSX KSW_HAVE_DLOPEN MDL_HAVE_OPENGL BNV_HAVE_QT KSW_HAVE_QGL KSW_HAVE_X11FONT KSW_HAVE_GETTIMEOFDAY dnl AC_C_BIGENDIAN_CROSS( AC_DEFINE( MM3D_BIGENDIAN ), AC_DEFINE( MM3D_LITTLEENDIAN ), AC_DEFINE(MM3D_UNKNOWNENDIAN) ) if test x"$prefix" != xNONE; then AC_DEFINE_UNQUOTED( [PREFIX], ["$prefix"], [Define installation prefix] ) else AC_DEFINE_UNQUOTED( [PREFIX], ["$ac_default_prefix"], [Define installation prefix] ) fi AC_SUBST(QT_LIBS) AC_SUBST(QT_CXXFLAGS) AC_SUBST(QT_CXXFLAGS) AC_SUBST(DLOPEN_LIBS) AC_SUBST(HAVE_QT5) AC_SUBST(BYTEORDER) AC_SUBST(PROFILE) AC_SUBST(CORE_PROFILE) if test x"${QT_LIBS}" = x; then echo "" AC_MSG_ERROR([Qt is required. If you have Qt installed see --help for more options]) echo "" fi if test x"$have_GLU" != xyes; then echo "" AC_MSG_ERROR([OpenGL (with GLU) is required.]) echo "" fi if test x"${ksw_cv_qgl_test_result}" = xfailure; then echo "" AC_MSG_ERROR([Qt with OpenGL is required.]) echo "" fi AC_CONFIG_FILES([ Makefile src/Makefile src/libmm3d/Makefile src/mm3dcore/Makefile src/depui/Makefile src/qtui/Makefile src/implui/Makefile src/tools/Makefile src/commands/Makefile src/pixmap/Makefile plugins/Makefile man/Makefile i18n/Makefile desktop/Makefile doc/Makefile doc/html/Makefile doc/html/olh_images/Makefile doc/html/olh_images/screencaps/Makefile doc/html/olh_images/tools/Makefile ]) AC_OUTPUT if test x"${have_dlopen}" != xyes; then echo "" echo "Warning: dlopen was not detected. You can contiue with the" echo "install, but plugins will not work." echo "" fi mm3d-master/depcomp000077500000000000000000000371001324021725400145650ustar00rootroot00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2005-07-09.11 # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputing dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> $depfile echo >> $depfile # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> $depfile else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` tmpdepfile="$stripped.u" if test "$libtool" = yes; then "$@" -Wc,-M else "$@" -M fi stat=$? if test -f "$tmpdepfile"; then : else stripped=`echo "$stripped" | sed 's,^.*/,,'` tmpdepfile="$stripped.u" fi if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi if test -f "$tmpdepfile"; then outname="$stripped.o" # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mecanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # X makedepend shift cleared=no for arg in "$@"; do case $cleared in no) set ""; shift cleared=yes ;; esac case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix="`echo $object | sed 's/^.*\././'`" touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test $1 != '--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o, # because we must use -o when running libtool. "$@" || exit $? IFS=" " for arg do case "$arg" in "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: mm3d-master/desktop/000077500000000000000000000000001324021725400146605ustar00rootroot00000000000000mm3d-master/desktop/Makefile.am000066400000000000000000000010731324021725400167150ustar00rootroot00000000000000EXTRA_DIST = \ mm3d.desktop \ x-mm3d.desktop \ mm3d.xpm \ mm3d-16.xpm all: install: $(INSTALL) -d $(DESTDIR)$(datadir)/applications/ $(INSTALL) -d $(DESTDIR)$(datadir)/mimelnk/application/ $(INSTALL) -d $(DESTDIR)$(datadir)/pixmaps/ ${INSTALL} -m 0644 mm3d.desktop $(DESTDIR)$(datadir)/applications/ ${INSTALL} -m 0644 x-mm3d.desktop $(DESTDIR)$(datadir)/mimelnk/application/ ${INSTALL} -m 0644 mm3d.png $(DESTDIR)$(datadir)/pixmaps/ ${INSTALL} -m 0644 mm3d-32.xpm $(DESTDIR)$(datadir)/pixmaps/ ${INSTALL} -m 0644 mm3d-16.xpm $(DESTDIR)$(datadir)/pixmaps/ mm3d-master/desktop/mm3d-16.xpm000066400000000000000000000051271324021725400164770ustar00rootroot00000000000000/* XPM */ static char * mm3d_16_xpm[] = { "16 16 126 2", " c None", ". c #0000FA", "+ c #0000E8", "@ c #00005E", "# c #9A0000", "$ c #AF0000", "% c #BE0000", "& c #C00000", "* c #B60000", "= c #A60000", "- c #0000D6", "; c #340039", "> c #A00000", ", c #C30000", "' c #D60000", ") c #E00000", "! c #E10000", "~ c #DC0000", "{ c #CE0000", "] c #B00000", "^ c #0000C2", "/ c #02005C", "( c #780014", "_ c #C20000", ": c #D90000", "< c #E80000", "[ c #EF0000", "} c #F00000", "| c #EC0000", "1 c #E20000", "2 c #CF0000", "3 c #0000AB", "4 c #250042", "5 c #AC0000", "6 c #D00000", "7 c #E40000", "8 c #F70000", "9 c #F80000", "0 c #F50000", "a c #ED0000", "b c #DE0000", "c c #960000", "d c #000098", "e c #4F0027", "f c #BA0000", "g c #D80000", "h c #EA0000", "i c #F40000", "j c #FA0000", "k c #FC0000", "l c #C80000", "m c #A50000", "n c #000084", "o c #580022", "p c #D70000", "q c #F90000", "r c #FB0000", "s c #F10000", "t c #CA0000", "u c #A70000", "v c #00006E", "w c #500024", "x c #B40000", "y c #D20000", "z c #E60000", "A c #F60000", "B c #F30000", "C c #EB0000", "D c #C10000", "E c #9E0000", "F c #0000F5", "G c #000060", "H c #28003E", "I c #A40000", "J c #C60000", "K c #DB0000", "L c #EE0000", "M c #D10000", "N c #840000", "O c #0000E4", "P c #04005A", "Q c #79000A", "R c #B30000", "S c #BC0000", "T c #920000", "U c #0000CE", "V c #1A009B", "W c #880008", "X c #AE0000", "Y c #C70000", "Z c #970000", "` c #0000BA", " . c #0000EC", ".. c #1600C3", "+. c #680028", "@. c #940000", "#. c #A10000", "$. c #A20000", "%. c #6C0030", "&. c #38006D", "*. c #0000A4", "=. c #000057", "-. c #000051", ";. c #00004C", ">. c #000096", ",. c #0000B7", "'. c #0000D4", "). c #1600BA", "!. c #2A009C", "~. c #1600C5", "{. c #0000F1", "]. c #0000D2", "^. c #0000B1", "/. c #00008E", "(. c #000039", "_. c #00003C", ":. c #000054", "<. c #000075", "[. c #000097", "}. c #0000B4", "|. c #0000E9", "1. c #0000C9", "2. c #0000A8", "3. c #000086", "4. c #000064", "5. c #00004D", " . ", " + @ # $ % & * = ", " - @ @ ; > , ' ) ! ~ { ] ", " . ^ @ / ( _ : < [ } | 1 2 ] ", " . 3 @ 4 5 6 7 } 8 9 0 a b & c ", " . d @ e f g h i j k 9 } 1 l m ", " . n @ o f p < i q r 9 s 1 t u ", " . v @ w x y z [ 0 A B C ~ D E ", " F G @ H I J K z a L C ! M ] N ", " O @ @ P Q R t g b ) ~ 6 S T ", " U @ @ @ V W X % Y l , * Z ", ". ` @ @ @ ...+.@.#.$.Z %.&. ", ". *.=.-.;.>.,.'.).!.!.~.. ", ". {.].^./.v ;.(._.:.<.[.}. ", " . . . . . |.1.2.3.4.5. ", " . . . . "}; mm3d-master/desktop/mm3d-32.xpm000066400000000000000000000133161324021725400164740ustar00rootroot00000000000000/* XPM */ static char * mm3dlogo_32x32_xpm[] = { "32 32 225 2", " c None", ". c #0000FA", "+ c #0000F9", "@ c #000061", "# c #8E0000", "$ c #0000DE", "% c #00005E", "& c #8C0000", "* c #9A0000", "= c #A60000", "- c #AE0000", "; c #B30000", "> c #B50000", ", c #B20000", "' c #AC0000", ") c #A20000", "! c #990000", "~ c #0000D0", "{ c #980000", "] c #AB0000", "^ c #B90000", "/ c #C20000", "( c #C80000", "_ c #CD0000", ": c #CA0000", "< c #C70000", "[ c #C10000", "} c #A50000", "| c #910000", "1 c #0000BF", "2 c #890000", "3 c #C30000", "4 c #CE0000", "5 c #D40000", "6 c #D80000", "7 c #DC0000", "8 c #D90000", "9 c #D30000", "0 c #CC0000", "a c #B10000", "b c #960000", "c c #0000A4", "d c #680014", "e c #9F0000", "f c #B60000", "g c #C50000", "h c #D00000", "i c #DF0000", "j c #E40000", "k c #E70000", "l c #E60000", "m c #C60000", "n c #000091", "o c #220043", "p c #970000", "q c #D10000", "r c #E10000", "s c #EB0000", "t c #ED0000", "u c #EE0000", "v c #E20000", "w c #DB0000", "x c #B00000", "y c #000083", "z c #070058", "A c #7A000B", "B c #C00000", "C c #EA0000", "D c #F00000", "E c #F30000", "F c #F40000", "G c #F10000", "H c #BD0000", "I c #000066", "J c #350034", "K c #9B0000", "L c #B40000", "M c #DE0000", "N c #F70000", "O c #F80000", "P c #F50000", "Q c #E80000", "R c #E00000", "S c #D70000", "T c #AF0000", "U c #0000EC", "V c #600017", "W c #A40000", "X c #BC0000", "Y c #E90000", "Z c #EF0000", "` c #F90000", " . c #FA0000", ".. c #CF0000", "+. c #BA0000", "@. c #0000E2", "#. c #05005A", "$. c #830004", "%. c #AD0000", "&. c #DD0000", "*. c #EC0000", "=. c #F60000", "-. c #FB0000", ";. c #F20000", ">. c #BF0000", ",. c #0000C4", "'. c #22003D", "). c #920000", "!. c #D20000", "~. c #FC0000", "{. c #FD0000", "]. c #0000B1", "^. c #1E0044", "/. c #C40000", "(. c #A70000", "_. c #1D0044", ":. c #E50000", "<. c #000088", "[. c #8D0000", "}. c #E30000", "|. c #000073", "1. c #13004D", "2. c #850000", "3. c #D60000", "4. c #D50000", "5. c #0000F8", "6. c #000068", "7. c #01005D", "8. c #66000F", "9. c #9E0000", "0. c #DA0000", "a. c #0000E7", "b. c #39002C", "c. c #C90000", "d. c #B80000", "e. c #A00000", "f. c #7F0000", "g. c #0000D7", "h. c #11004D", "i. c #7E0001", "j. c #CB0000", "k. c #BB0000", "l. c #3D0026", "m. c #8A0000", "n. c #A30000", "o. c #7B0000", "p. c #0000AB", "q. c #0300A5", "r. c #5B002F", "s. c #900000", "t. c #000099", "u. c #0000BC", "v. c #0B00DD", "w. c #600020", "x. c #8B0000", "y. c #BE0000", "z. c #7D0000", "A. c #000086", "B. c #0000CF", "C. c #0600E6", "D. c #4F003C", "E. c #820000", "F. c #930000", "G. c #6C000E", "H. c #00006E", "I. c #0000ED", "J. c #0300F0", "K. c #29008A", "L. c #620018", "M. c #950000", "N. c #61002D", "O. c #2A0092", "P. c #0500CC", "Q. c #0000F1", "R. c #000064", "S. c #00005D", "T. c #00005F", "U. c #0000E0", "V. c #0000F5", "W. c #0100F6", "X. c #1E00A9", "Y. c #3A0068", "Z. c #50003E", "`. c #56003E", " + c #51003E", ".+ c #3C006A", "++ c #1A00B7", "@+ c #0100F8", "#+ c #0000E3", "$+ c #00005A", "%+ c #000054", "&+ c #00004D", "*+ c #000047", "=+ c #000041", "-+ c #00003C", ";+ c #000039", ">+ c #000048", ",+ c #0000A0", "'+ c #0000C1", ")+ c #0000E1", "!+ c #0000F4", "~+ c #0000F3", "{+ c #0000DD", "]+ c #000098", "^+ c #000078", "/+ c #000058", "(+ c #00003F", "_+ c #000046", ":+ c #000060", "<+ c #00007F", "[+ c #00009F", "}+ c #0000C3", "|+ c #0000E5", "1+ c #0000D2", "2+ c #0000B3", "3+ c #000093", "4+ c #00005C", "5+ c #000082", "6+ c #0000E9", "7+ c #0000C8", "8+ c #0000A8", "9+ c #000069", "0+ c #00003A", "a+ c #00007D", "b+ c #000089", " ", " . + @ # ", " . $ % % & * = - ; > , ' ) ! ", " . ~ % % % { ] ^ / ( _ _ : < [ > } | ", " . 1 % % % % 2 ) > 3 4 5 6 7 7 7 8 9 0 [ a b ", " . . c % % % % % d e f g h 6 i j k l l j i 8 9 m , { ", " . . n % % % % o p , g q 8 r k s t u t s k v w q 3 x ", " . . y % % % z A ' B h 8 v C t D E F E G u C v 8 4 H ) ", " . . I % % % J K L < 5 M l t G F N O N P E D Q R S < T | ", " . U @ % % % V W X 0 6 v Y Z F N ` .` N P G s j 7 ..+.* ", " . @.% % % #.$.%./ h &.l *.G =.` .-.-.` =.;.t l &.q >.W ", " . ,.% % % '.)., g !.i k t E O .-.~.{.-.N E u Q &.q [ = ", " . ].% % % ^.).a /.!.M l *.;.N ` -.~.{.-.O F D Y &.!.[ (. ", " . c % % % _.| T 3 q 7 :.s G P N ` . .` =.;.u k &.!.[ (. ", " . . <.% % % _.[.' [ ..8 }.C u ;.P N O N =.E Z C }.8 4 X W ", " . . |.% % % 1.2.(.X 0 3.r Q *.Z E P P F E D *.l i 4.< L p ", " . 5.6.% % % 7.8.9.> /.h w }.k s Z ;.G D Z t k r 0...>.] 2 ", " . a.% % % % % b.| %.X c.9 w r :.Q s s C Y l r w 5 < d.e.f. ", " . g.% % % % % h.i.e , / j.9 0.M r }.j }.r M 8 !.c.k.] # ", " . ,.% % % % % % l.m.n.> [ c.q 3.8 w 7 7 8 3.h < H %.b o. ", " . p.% % % % % % q.r.s.n.a X /.: _ h q h _ c.3 k.- * o. ", " . . t.% % % % % % u.v.w.x.9.' ; ^ y.[ [ B y.^ a (.b z. ", " . . A.% % % % % % B.. C.D.E.F.9.= ' x T %.] n.* 2 G. ", " . . H.% % % % % % I.. . J.K.L.f.[.).M.b M.[.E.N.O.P. ", " . Q.R.% % % % S.T.U.V.. . . W.X.Y.Z.`.`. +.+++@+. ", " . #+$+%+&+*+=+-+;+;+>+R.y ,+'+)+!+. . . . . . . . ", " . ~+{+u.]+^+/+(+;+;+;+;+;+;+;+;+_+:+<+[+}+|+V.. + ", " . . . . . . . U 1+2+3+|.&+;+;+;+;+;+;+;+;+;+>+4+5+ ", " . . . . . . . . . + 6+7+8+<.9+*+;+;+;+;+0+%+ ", " . . . . . . . . . !+#+}+,+a+$+ ", " . . . . . . . . . b+ ", " . . . "}; mm3d-master/desktop/mm3d.desktop000066400000000000000000000004561324021725400171200ustar00rootroot00000000000000[Desktop Entry] Encoding=UTF-8 Type=Application Exec=mm3d %U Icon=mm3d DocPath=mm3d/index.html GenericName=3D Modeler Comment=3D modeling program Terminal=false Name=Misfit Model 3D MimeType=application/x-mm3d Categories=Qt;Application;Graphics; X-AppInstall-Package=mm3d X-AppInstall-Section=universe mm3d-master/desktop/mm3d.png000066400000000000000000000131511324021725400162270ustar00rootroot00000000000000PNG  IHDR>a pHYs  d_IDATx{l]?k9ý\rW6JmJkmƨiԪm>X,"HmQgk[$6 i 5(p X, OQ:Ǥlk!rߏuW,KY  OL N󜩂#wq -=f<*KG6a`x Sk@y-@bm-@ h b@v3Zc/5Vܹs#%oE~pBwÁ}Z367T3fՉ_%W蘋/?U^<S@EN_Ho_o k6ǭM['5 BBK z`'(nxCJ?OXj<<: C`B'+0bIxg)͊I.b9fk*gjXns.Hf-s˸S8A)12֜ΐC!!OWJ0tY~ȅ){@O:& 5NBo=_6s?*q-d -ЖGgGw `]A0>NJKgѸx C`=Jbc<\~s4jIM\QG~ѥrt] Vxbej#b}O#eTVة`w鍚b)?D^̈u=P)׻<r>#;;OP)=?>`P3>a@%60T(\z2 Bp!`mgm2%:b#4$9R@#;l "~zP- FP [G<~.7Zw4p;0|lvrѾ"=S uSB–E%TT䆦8`D¸"ҽ~w1?*rHKUaRC%8MR鿺&-:8AQեʔ:لJ:!bN4?-)6p\'~OQx6䜁5 5ISØ[~{jOKejB\8NO0|B%ڋU|BLc,}),s%?%z5+oi *2O|JI9EO bP sp?|ى Xү9hhфB!b]ߔ}(3}; (B@/`u6ùBz '91 OX(|R:"@#,C3@%geUW_F|𜼥sN=j= "A@ث*X9eڗo"š$\(e+=lR^apboEjc fCl.n41s\ү, P|%.RSt:{+NM_}g?u9_/@;˦%tz5Rh\*"9z%$o{ˀw=_Rbc*7roـ/9V|˾D\xWH*8|F3 OW>=|SM ޙm*n1VΜƟ!*||mUx@a?BzdcuCbO_6,0J0_jJKT1vꀞ#ֲ"^$GDlsW 9cr4pӀ-)&<.;u, 5gNk4/<@KæWK̍q宁ȶGU+kHF#PB@@:"$&Xey3c5Wg2=?s'yWh=acXIQoL`hHW!ם~Cө/2-,^χ*kv~6MF:{V^.s=-"nKjƖ'buUn'MV@xP"%Ym\9|U 셦楥f}.` ŒY')`-ΦnO#(zh/<ŏ͙{h.Xc<;y#mt4X"z⿏c? p|/s>G9o@<%x-x-s |UJ(l"^k SuRѣarjS ԍ7m6;xgqj%6i8$u15qo/YWO?O֨| SSnzcSWgќj~*8|XR9c䀐>mPd& (Xb~ P;\Ӽ{]NDotUIoƲ@ Q`yܴsL'dI6>ꯝs~Ptho3~C v('Tm] 5)s~ `u p{9tj2@J{ݵ-F/޾OiWW:1tJd&T6;=2;SY'WY $*.html install: all ${INSTALL} -d $(DESTDIR)${DOCDIR}/olh_images/screencaps ${INSTALL} -d $(DESTDIR)${DOCDIR}/olh_images/tools ${INSTALL} -m 0644 *.html $(DESTDIR)${DOCDIR} ${INSTALL} -m 0644 olh_images/screencaps/*.png $(DESTDIR)${DOCDIR}/olh_images/screencaps ${INSTALL} -m 0644 olh_images/tools/*.png $(DESTDIR)${DOCDIR}/olh_images/tools ${INSTALL} -m 0644 olh_images/tools/*.jpg $(DESTDIR)${DOCDIR}/olh_images/tools mm3d-master/doc/html/TODO000066400000000000000000000012671324021725400154160ustar00rootroot00000000000000TODO: grep FIXME Group Clean-up Window Selected dimensions in context panel Tutorial UI Tour (main window documentation) x Basic Modeling x Primitive Creation x Manipulations x Extrude, split, turn x Background Images ? Polytool / Free Vertices / Make Face Groups and Textures x Grouping Texturing / Materials x Projections x Coord edit x Texture paint x Texture reload Skeletal structure and Animations x Bone Joints x Influences Animations Points / uses MD2/MD3/Cal3d guides Links to other modeling tutorials mm3d-master/doc/html/olh_alignwin.htm000066400000000000000000000035561324021725400201150ustar00rootroot00000000000000

Align Selection Window

The Align Selection Window moves the selected portion of the model so that the minimum, maximum, or center values of a given coordinate axis are aligned along a specified value of the axis. For example, if you have a cube you can use the Align Selection window to align the left or right (minimum or maximum, respectively) side of the cube with the axis (0.0) or any other value for X. The shape of the selected portion of the model remains unchanged.

Tip: If all you want to do is align the center of the selected geometry to a specific location, it may be easier to use the Position Properties panel.

The Align Selection Window is composed of three frames, one for each model dimension. Each frame contains a text entry box to enter a numerical value and three radio buttons for aligning the minimum, center, and maximum vertex values with the numerical value. The Align Now buttons change the alignment of the selected model region.

Alignment values are as follows:

  minimum center maximum
X left center right
Y bottom center top
Z back (far) center front (near)

Press Ok to keep your changes or press Cancel to ignore any changes.

mm3d-master/doc/html/olh_alignwin.page000066400000000000000000000001011324021725400202200ustar00rootroot00000000000000PAGE_TITLE=Align Selection Window PAGE_CONTENT=Animation Details

Overview

You can create animations to define how your model moves over time. Misfit Model 3D allows you to use bone joints to create skeletal animations or to set vertex positions exatly with mesh deformation animations (called "Frame" animations in Misfit Model 3D).

Animations have one or more frames which are consecutive points in time. Each frame lets you specify what the model should look like at that time. The frame rate, or FPS for "Frames Per Second", indicates how many frames are shown in one second when the animation is running at full speed.

Creating an Animation

Select "Animation | Start Animation Mode...". The Animation Panel will appear at the bottom of the screen. Select <New Animation> from the drop-down menu. Enter a name for your new animation and then select "Skeletal" for a skeletal animation or "Frame" for a mesh deformation animation.

You can create multiple animations of either type. When you have animations of both types, the animation names in the drop-down selection box list all skeletal animations first, followed by all frame animations.

Animation Details

In skeletal animations you only change bone joints. Any vertices or points attached to the bone joints will move with the joints. Generally you only want to use rotations (think about how you move your arm by rotating the shoulder and elbow, not by dislocating the joints).

Any time you rotate or move a bone joint it sets a rotation or translation keyframe for that animation frame. If you want the default position to be a keyframe in that frame, you can select the joint and then select "Animation | Set Rotation Keyframe". Often you will want to do this on the first and last frame of an animation for every joint that will be affected by the animation.

In frame animations you set the position for each vertex and point in each frame. Bone joints have no effect (and are not even rendered).

You can copy and paste entire animation frames by selecting the copy or paste option from the "Animation" menu. Clearing the frame will erase all keyframes for the current frame of a skeletal animation and will restore the model to the default position for a frame animation.

See Also

mm3d-master/doc/html/olh_animationdetails.page000066400000000000000000000001041324021725400217400ustar00rootroot00000000000000PAGE_TITLE=Animation Details PAGE_CONTENT=Convert To Frame Window

The Convert To Frame Window will take the currently selected animations in the Animation Sets Window and convert them into frame animations. You will be prompted with this window once for every skeletal animation you have selected. The original animations remain unmodified.

This features is useful if you have a set of skeletal animations and want to export the model as an MD2 or MD3, which only support frame animations.

Provide a name for the frame animation in the Frame Anim Name text box. The name can be the same as the skeletal animation.

Set the frame count in the Frame Count spin box. The frame rate will be modified so that the frame animation and skeletal animation complete in the same amount of time. In other words:

anim1_frame_count * anim1_fps = anim2_frame_count * anim2_fps

Skeletal animations by default are 30 frames per second. Frame animations in MD2s are 10 frames per second. Frame rates in MD3 are variable and controlled by animation.cfg file. Frame rates in Cal3D are assumed to be 30 frames per second when importing.

The Continue button will convert the current skeletal animation to a frame animation. If you have more skeletal animations selected you will be prompted with the convert window once for each of them.

The Cancel button will cancel the conversion of one animation.

The Cancel All button will cancel the conversion of all remaining animations.

mm3d-master/doc/html/olh_animconvertwin.page000066400000000000000000000001101324021725400214530ustar00rootroot00000000000000PAGE_TITLE=Convert Frame To Window PAGE_CONTENT=Export Animation Window

Overview

The Export Animation Window allows you to save an animation as a series of jpeg or png files.

Exporting Animations

Source

The Source frame has an Animation combo box to specify which animation you want to export and a Viewport combo box to specify which viewport the animation should play in. The viewports are referenced by number and also indicate the direction from which the viewport is looking at the model. The viewports are numbered from left to right, top to bottom, starting at 1.

Duration

The Duration frame controls how long the animation should play. You can specify the duration in Seconds or complete animation Iterations by clicking on the appropriate radio button and entering the number of seconds or iterations in the number entry box.

Output

The Output determines how the exported animation images will be saved. You can specify the Frame Rate, the filename Format (JPEG or PNG, with or without leading zeros), and the output Directory.

Ok and Cancel

The Ok button will start the export process and close the window.

The Cancel button will close the window without exporting animations.

mm3d-master/doc/html/olh_animexportwin.page000066400000000000000000000001071324021725400213220ustar00rootroot00000000000000PAGE_TITLE=Export Animation Window PAGE_CONTENT=Animation Sets Window

Overview

The Animation Sets Window allows you to create and organize animations. You can copy complete animations, split them into separate animations, and join multiple animations into one.

The Animation Sets Window has a combo box that lists animation types, a list box that lists animations of the selected type, and a set of buttons to perform operations on animations. Many buttons operate on all the animations selected in the animation list box.

The animation type combo box allows you to select between skeletal and frame animations. When you select an animation type you will see all animations of that type listed in the animation list box. You can use the standard Ctrl-Click and Shift-Click mouse operations to select multiple animations to operate on.

For more information on animating a model, see the Animations section of the introduction.

Some operations only work on certain types of models.

Animation Operations

Up and Down

The Up and Down buttons allow you to re-order existing animations. Select the animations you want to move and click Up to move the animations closer to the top of the list or Down to move the animations closer to the bottom of the list.

New

The New button creates a new animation. It will prompt you for an animation name. The new animation will be a skeletal or frame animation depending on the animation type you have selected in the animation type window.

Rename

The Rename button changes the name of selected animations. It will prompt you for a new animation name. All selected animations are renamed to the name you enter.

Delete

The Delete button will delete all selected animations.

Copy

The Copy button will create a copy of the selected animations. A new animation is created for each selected animation and contains the same position information, frame count, and frame rate as the original animations. The newly created animations are appended to the end of the animation list.

Split

The Split button will split a selected animation into two separate animations at the frame you specify. The specified frame and all successive frames will be removed from the original animation. The new animation will begin with the specified frame and contain all successive frames.

You will be prompted for a frame number for each selected animation. The new animation will appear immediately following the animation you are splitting.

Join

The Join button will combine all the selected animations into one animation. Each animation will be appended to the one preceding it.

Merge

The Merge button will combine two or more animations into one animation of the same length. For example if you have two skeletal animations on a model with two arms and one animation moves the right arm while another moves the left arm, you can use the Merge button to have both arms move at the same time. In order to merge two animations they must have the same frame count.

This button only works for skeletal animations.

Convert To Frame Animation

The Convert To Frame Animation button will take the currently selected animations and convert them into frame animations. The original animation remains unmodified. This button is useful if you have a set of skeletal animations and want to export the model as an MD2 or MD3, which only support frame animations.

When you select this option you will be prompted by the Covert To Frame Window to provide a name for the new animation and the frame count. The skeletal animation and the frame animation will take the same amount of time to complete, so the frame rate (in frames per second) depends on the frame count of the new animation. In other words:

anim1_frame_count * anim1_fps = anim2_frame_count * anim2_fps

This button only works for skeletal animations.

Ok and Cancel

The Ok button will close the Animation Sets window and keep all of your changes.

The Cancel button will close the Animation Sets window and undo all changes you made since opening it.

mm3d-master/doc/html/olh_animsetwin.page000066400000000000000000000001021324021725400205670ustar00rootroot00000000000000PAGE_TITLE=Animation Sets Window PAGE_CONTENT=Animation Panel

Overview

The Animation Panel allows you to animate models. You can change frame counts and frame rates as well as set skeletal keyframes or frame vertex positions. You can also play animations from this window. For performance reasons animation playback is only rendered in perspective viewports.

While the Animation Panel is open you can use the view window's toolbar to manipulate the model in animation mode. Most selection and manipulation tools work the same as they do in model edit mode, though some (such as the rotate tool in skeletal animation mode) will behave differently. Geometry creation tools have no effect in animation mode.

The behavior of various tools in animation mode is described in the Tools documentation.

The Animation Panel has a drop down box that lists all the animations that are defined for the model. It lists all Skeletal animations first, then all Frame (mesh deformation) animations. All operations operate on the animation that is named in the drop down box.

You can use the frame slider to select the animation frame that you want to view or edit. All viewports on the view window will display the frame of the model you have selected.

You can use the selection tools to select vertices for Frame animations or bone joints for Skeletal animations. You can use the move or rotate tool to change the position or orientation of selected primitives.

In Skeletal animation mode the rotate tool works differently than it does in standard edit mode. The rotation only applies to bone joints, and the rotation is always centered on a joint. In other words, you are rotating the bone joint itself, not the position of the bone joint. In Skeletal animation mode, the delete command also behaves differently. The delete command will delete any translation or rotation keyframes for all the selected joints in the current frame. Keyframes in other animation frames will not be affected.

You can use Undo and Redo from the Animation Panel just as you would in the standard model edit mode. You can select Undo and Redo from the menu on the Main Window, or use Ctrl-Z and Ctrl-Y.

For more information about creating animations with Misfit Model 3D, see the Animations section of the introduction.

Animation Operations

New Animation

To create a new animation, select <New Animation> in the animation name drop down box. It will prompt you for an animation name. The prompt will also allow you specify if the animation is a skeletal animation or a frame animation.

Delete

The X button will delete the current animation (there is a confirmation prompt).

Frames Spin Box

The Frames Spin Box will change the frame count of the current animation. You can use the up and down arrows, or type the number directly in the box.

Frame Slider

The Frame Slider will change the current frame of the current animation. You can use this to edit the model position for any frame in the animation. The Copy Frame, Paste Frame, and Clear Frame commands also operate on the current frame.

FPS Text Box

The FPS Text Box will change the frame rate of the current animation.

Copy/Paste/Clear Frame

You can copy one keyframe to another using the Animation menu.

Play / Pause

The Play button runs the current animation at its specified frame rate. The Play button becomes a Pause during playback so that you can pause an animation and resume it later. Paused animations resume from the time at which they were paused.

Use the Stop button to stop an animation completely. Use the Loop Checkbox to control whether the animation should start from the beginning again when it completes.

Animation playback is only rendered in perspective viewports. Orthographic viewports will not animate. This is for performance reasons, and may become a configurable option at a later time.

Stop

The Stop button will stop a running animation. An animation that is stoped and then played again will play starting from the first frame.

Loop Checkbox

The Loop Checkbox controls whether the animation loops when it completes or not. If the animation completes and the Loop Checkbox is checked, the animation will restart from the first frame. If the animation completes and the Loop Checkbox is not checked, the animation will stop.

If you have loop checked, skeletal animation keyframe interpolation will wrap to the first frame. This interpolation begins on the last keyframe set for a given joint and ends on the first keyframe for that joint. If you have an animation with 10 frames and a rotation keyframe on Joint A for frames 1 and 10, then the animation will interpolate from 1 to 10, and then from 10 to 1. If Joint B has keyframes in frames 3 and 7, it will interpolate from 3 to 7, and then again from 7 to 3.

Close

To close the Animation Panel and return to model edit mode, select "Animation | Stop Animation Mode" or click on the panel's close button.

See Also

mm3d-master/doc/html/olh_animwin.page000066400000000000000000000000771324021725400200660ustar00rootroot00000000000000PAGE_TITLE=Animation Mode Window PAGE_CONTENT=Auto-Assign Bone Joints Window

The Auto-Assign Bone Joints Window allows you to quickly assign vertices and points to bone joints. The two factors that determine which bone joint a vertex or point is assigned to are the orientation of the joint and the distance to the joint.

The Only assign to selected joints checkbox indicates if you want to assign to any bone in the model, or limit the assignments to joints that are selected. If no bone joints are selected, this checkbox is disabled.

The auto-assign feature will assign a primary bone joint influence and up to two additional influences (a child and parent of the primary joint) for a total of up to three bone joints. The Single/Multiple slider allows you to increase or decrease the range of child and parent bone joints. If the slider is completely on the Single side, a vertex can only be assigned to one joint. As the slider moves closer to the Multiple side, child and parent joints of the primary joint are more likely to be assigned.

Press Ok to auto-assign bone joints or press Cancel to leave bone joint assignments as they are.

mm3d-master/doc/html/olh_autoassignjointwin.page000066400000000000000000000001231324021725400223530ustar00rootroot00000000000000PAGE_TITLE=Auto-Assign Bone Joints Window PAGE_CONTENT=Background Image Details

Overview

A background image is an image that is projected onto an orthographic viewport to aid in creating a model. It helps the user with getting the scale and shape of meshes right by providing a visual reference. A different background image may be applied to each of the 6 pre-defined orthographic viewport directions.

Assigning a Background Image

A background image can by assigned to a viewport direction using the Select Background Image Window. After opening this window, select the tab for the direction you want, and then click the "File" button to select an image file. The image file can be any format supported by MM3D. Background image dimensions do not need to be powers of two.

Other Background Image Details

You can move and scale a background image to position it where you need it for modeling purposes. Use the move and scale background image tools for this purpose. Scaling always preserves the aspect ratio.

See Also

mm3d-master/doc/html/olh_backgroundimagedetails.page000066400000000000000000000001211324021725400231020ustar00rootroot00000000000000PAGE_TITLE=Background Image Details PAGE_CONTENT=Select Background Image Window The Select Background Image Window assigns image files to a specific viewport direction: Front, Back, Left, Right, Top, or Bottom. A different image can be specified for each direction.

Open the Select Background Image Window by selecting "Set Background Image" item from the "Model" menu.

The Select Background Image Window is composed of the direction frame, and the None and File... buttons. Use the direction tab to select which direction you want to chose a background for, and the File... button to select the image. To unassign a background image, select the view direction and press the None button.

To reposition or resize the background image in the viewport, use the Move Background Image tool or the Scale Background Image tool.

Press Ok to keep your changes or press Cancel to ignore any changes.

See Also

mm3d-master/doc/html/olh_backgroundwin.page000066400000000000000000000001161324021725400212530ustar00rootroot00000000000000PAGE_TITLE=Select Background Image Window PAGE_CONTENT=Boolean Operation Window

The Boolean Operation Window is a dockable window that allows you to combine two mesh objects into a single object. Open the Boolean Operation Window by selecting "Model | Boolean Operation..." The supported operations are listed below.

  • Fuse -- Combine overlapping meshes, any triangles that intersect will be split so that the meshes share vertices along the edges where they intersect. No faces are removed by the Fuse operation.
  • Union -- Combine overlapping meshes like the Fuse operation, then removes internal faces (faces inside the volume of either enclosed mesh.
  • Subtraction -- Removes the selected mesh and any part of Object A that is inside the volume of the selected mesh.
  • Intersection -- Removes any volume inside of Object A or the current selected mesh that is not contained within both objects
Select object A

Select Object A

Select object B

Select Object B

Fuse

Fuse

Union

Union

Subtraction

Subtraction

Intersection

Intersection

For the union, intersection, and subtraction operations to work properly, all meshes involved must be enclosed (otherwise the behavior of the face-removal step is undefined). If the meshes are not enclosed you can still use the fuse operation and manually remove the faces that must be removed.

To peform a boolean operation, select an enclosed mesh and then click Set Object A. Then select another enclosed mesh and click [op] With Selected where [op] is the name of the selected operation (the button name changes when you select an operation).

After using a boolean operation you may want to use Simplify Mesh to combine some newly created faces.

mm3d-master/doc/html/olh_boolwin.page000066400000000000000000000001021324021725400200620ustar00rootroot00000000000000PAGE_TITLE=Boolean Operation Window PAGE_CONTENT=Contents

Cal3D Support

There are few different file formats for Cal3D and several different versions for those formats. Misfit Model 3D has support for most Cal3D functionality, but some features are missing or imperfect. The following is a short list of things to be aware of when working with Cal3D files in Misfit Model 3D. Some of these items are discussed in more detail in the sections below.

  • For the primary Cal3D model file, MM3D will read files with the .cal and .cfg extensions. INI-style files are supported, XML-style files are not (except for material files).
  • For skeleton, animation, mesh, and material files binary formats are supported for versions 700-1200. XML materials are also supported. No other XML formats are supported.
  • MM3D does not support springs or LOD reduction. These attributes will be silently discarded on import.
  • Texture map materials are supported, any additional maps in the material file will be silently discarded on import.
  • MM3D assumes 30 fps and assigns the keyframes to frame numbers.
  • MM3D will read compressed animations, but will not write compressed animations.

MM3D has a Cal3D Export Options window that allows you to write meshes in a single file, or in separate files, as well as specifying whether materials should be in XML or binary format.

File Formats and Versions

.cal and .cfg

Cal3D models are made up of skeleton, animation, mesh, and material files, as well as .cal or .cfg configuration files that define how to put the final model together from the individual files. There are two file formats for the .cal and .cfg files. One style is similar to a Windows .INI file. It has section names in square brackets and key/value pairs that specify filenames for parts of the model. The other style is an XML format. Misfit Model 3D will read and write the INI style files, but not the XML format.

Some attirbutes of the configuration file will be read, preserved, and written even though MM3D does not use them. Those attributes include things like scale and rotation.

Skeleton Files (.csf)

Binary skeleton file formats 700 through 1200 are supported. XML skeleton files are not supported.

The filename of the skeleton file written by MM3D will be the same as the main .cal or .cfg file with the extension replaced with .csf.

Animation Files (.caf)

Binary animation file formats 700 through 1200 are supported. XML animation files are not supported.

There is one animation file per animation. The animation filename is is the name of the animation plus the .caf extension. If a meta data key for "animation_[animation name] is defined, the filename specified in the meta data is used instead.

MM3D tracks animations on a per-frame basis, using the frames-per-second attribute to determine at which point in time a keyframe influences the skeleton. Cal3D animations do not have an FPS attribute, only keyframe times. MM3D assumes 30 fps to assign the keyframes to frame numbers.

MM3D will read compressed animation tracks. MM3D will write animation files in any version number you specify, but regardless of the version number MM3D will always write uncompressed animation tracks.

Mesh Files (.cmf)

Binary mesh file formats 700 through 1200 are supported. XML mesh files are not supported.

The meshes in the model may be written in one mesh file, or one file for every group. If there is a single mesh file, it will be the same name as the .cal or .cfg file with the extension replaced with .cmf. If there are multiple mesh files, the files will be named after the groups with .cmf appended.

Note that LOD (level of detail) attributes and springs are not supported by MM3D. LOD and spring data will be silently discarded when mesh files are read.

Material Files (.crf and .xrf)

Binary material file formats 700 through 1200 are supported. XML versions 900 through 1000 are supported.

Material file names are the material name with .crf or .xrf appended.

Texture map materials are supported. Other additional maps that are specified will be silently discarded by MM3D.

Often Cal3D texture images are in PNG or RAW format. MM3D supports both of these formats in addition to many other formats.

mm3d-master/doc/html/olh_cal3d.page000066400000000000000000000000631324021725400174050ustar00rootroot00000000000000PAGE_TITLE=Cal3D Notes PAGE_CONTENT=Cal3D Export Options

The Cal3D Export Options window is displayed when you save a model in Cal3D format. It allows you to specify how meshes and materials should be saved.

The Save Meshes options specify whether all meshes should be saved in one file or whether a separate mesh file should be written for each group.

The Save Materials options specify whether materials should be saved in binary or XML format. Note that material files are the only Cal3d XML format supported by Misfit Model 3D.

Click Ok to save the model with the specified options or click Cancel to ignore any changes.

mm3d-master/doc/html/olh_cal3dprompt.page000066400000000000000000000001011324021725400206400ustar00rootroot00000000000000PAGE_TITLE=MS3D Export Options PAGE_CONTENT=Command Line

Overview

The Misfit Model 3D command line allows you to specify models to open at start time, operations to run on those models, and other start-time configuration options.

A complete command line reference is included below.

Command Line Options

-h --help

Prints a brief summary of command line options.

-v --version

The version option prints the version information for Misfit Model 3D.

--convert

The convert option saves every model file specified on the command line in the specified format. The format is a string that is the filename extension. The existing filename extension will be replaced by the new extension to create the new filename. If a file already exists by this name it will be overwritten (if you're converting files in batches from the command line mm3d assumes you know what you're doing).

The convert option takes one argument, which is the extension that specifies the format you want to save. You can only specify this argument once. If it is used multiple times only the last format will be used.

--language

The language option specifies the language in which the UI will be displayed. If you do not specify this option, the system's default locale will be used to determine the appropriate language.

See the Misfit Model 3D website for a list of supported languages.

--no-plugins

The no-plugins option disables all plugins (this may be useful if you suspect a plugin is causing a crash on initialization).

--no-plugin

The no-plugin option disables a specific plugin. This option takes an argument which is the name of the plugin to disable (the filename, without the .so extension). Misfit model will still get the plugin information from this plugin, but will not initialize it and will report it as disabled in the Plugins Window.

--sysinfo

The sysinfo option prints system information. This is present for bug-reporting reasons. If you want to submit a bug, include the output of this option with your bug report.

--debug

The debug option prints debug log messages to standard error output. This is on by default in debug builds and off in release builds.

--warning

The warning option prints warning log messages to standard error output. This is on by default in debug builds and off in release builds.

--error

The error option prints error log messages to standard error output. This is on by default in all build configurations.

--no-debug

The no-debug option disables debug log messages.

--no-warning

The no-warning option desiables warning log messages.

--no-error

The no-error option disables error log messages.

mm3d-master/doc/html/olh_cmdline.page000066400000000000000000000000661324021725400200350ustar00rootroot00000000000000PAGE_TITLE=Command Line PAGE_CONTENT=Geometry Menu

Undo

Overview

Undo reverses the last operation (if available). The last operation could be the last use of the mouse on a model canvas, the last requested command (except in the case of undo or redo), or a set of changes within one dialog box.

Undo can be used multiple times. The number of undo items available is limited by memory.

Keyboard shortcuts

  • Ctrl-Z - Undo

Redo

Overview

Redo reverses the effects of undo (if the preceding operations were undo commands). Redo can be used multiple times.

Keyboard shortcuts

  • Ctrl-R - Redo

Copy Selected to Clipboard

Overview

Copy Selected will copy all selected faces (along with groups and textures) into an internal clipboard. This selection can then be merged with another model using the Paste command.

Keyboard shortcuts

  • Ctrl-C - Copy selection

Paste from Clipboard

Overview

Paste will merge the selected portion from a previous Copy command into the current model.

Keyboard shortcuts

  • None

Weld Vertices

Overview

Weld Vertices will join selected vertices into one vertex. The vertices must be very close to each other.

More than one set of vertices can be welded at one time. If you have a model which has been duplicated and flipped you can weld the seam between the two portions by moving the seams together, selecting all vertices along the seam, and using a single weld command. Only vertices near each other will be welded so that you can weld the entire seam in one operation.

Vertices can be disconnected again by using the unweld command.

Keyboard shortcuts

  • Ctrl-W

Unweld Vertices

Overview

Unweld Vertices will create a separate vertex for each face which uses a vertex.

Vertices can be reconnected by using the weld command.

Keyboard shortcuts

  • None

Snap Vertices Together

Overview

Snap Vertices Together will move a set of selected vertices to the same coordinates and optionally weld them together. This command has four different behavaiors:

  • Snap All Selected - All selected vertices snap to the same location, they remain separate vertices
  • Snap Nearest Selected - Every two closest selected vertices snap to the same location, they remain separate vertices
  • Snap All and Weld - All selected vertices snap to the same location, all vertices are welded into one
  • Snap Nearest and Weld - Every two closest selected vertices snap to the same location, each pair of vertices is welded into one vertex

Keyboard shortcuts

  • None

Make Face From Vertices

Overview

Make Face will create a new face from three selected vertices. You must have exactly three vertices selected for this command to operate.

Keyboard shortcuts

  • None

Select Free Vertices

Overview

Select Free Vertices will select all vertices that are not connected to a triangle. Normally vertices are deleted when all triangles connected to them are deleted. The exception to this is any vertex that was created using the Create Vertex tool.

Keyboard shortcuts

  • None

Edge Turn

Overview

Edge Turn will take two adjacent triangles and rotate the triangles on their shared vertices.

If two triangles use vertices 1 through 4 and the edge between them connects vertices 2 and 4, Edge Turn will rotate the triangles so that vertices 1 and 3 are connected.

Before

After

Keyboard shortcuts

  • None

Edge Divide

Overview

Edge Divide will split a triangle edge into two edges. Every triangle that uses this edge will be split into two triangles. To use the Edge Divide command, select the vertices at each end of the edge.

Keyboard shortcuts

  • None

Subdivide Faces

Overview

Subdivide Faces will divide a triangle face into four triangles which share vertices.

Keyboard shortcuts

  • None

Rotate Texture Coordinates

Overview

Rotate Texture Coordinates allows you to rotate the texture coordinates of a face or group of faces. If you use the Face version, the texture coordinates are rotated among each vertex of each selected face. If you use the Group version, the texture coordinates are rotated 90 degrees around the center of the material texture.

Keyboard shortcuts

  • None

Align Selected

Overview

Align Selected opens a window to move the selected portion of the model so that the minimum, maximum, or center values of a given coordinate axis are aligned along a specified value of the axis. For example, if you have a cube you can use the Align Selection window to align the left or right (minimum or maximum, respectively) side of the cube with the axis (0.0) or any other value for X. The shape of the selected portion of the model remains unchanged.

See the Align Selection Window for more details.

Keyboard shortcuts

  • None

Simplify Mesh

Overview

Simplify Mesh combines faces that do not add detail to a shape. This command does not perform LOD reduction.

Before

After

If you have a cube where each side is made up of 8 triangles, then all of these triangles are in the same plane and many edges form a single straight line. In this case, the eight faces on each side can be reduced to two faces. Often when you use a boolean operation to combine two objects you will want to use the simplify mesh command to eliminate unecessary faces from the model.

Keyboard shortcuts

  • None

Cap Holes

Overview

Cap Holes creates faces to fill in gaps in a mesh. This command can be confused by complex geometry with multiple holes. The best way to deal with more complex shapes is to select only the faces around a single hole at a time.

After using the cap holes command you may need to use the Normals Face Out command to correct the orientation of the new faces.

Keyboard shortcuts

  • None

Spherify

Overview

Spherify opens a window to interactively morph the selected portion of the model into a spherical shape. See the Spherify Window for details.

Keyboard shortcuts

  • None

Invert Normals

Overview

Invert Normals will cause normals to extend from the opposite plane of selected faces. This is useful if some sections of the model have been manipulated in such a way that polygons are facing the wrong direction.

If you have very dark polygon faces or if some polygon faces don't show up in a different rendering engine, it may be because your normals are facing the wrong direction. In these cases, inverting normals will fix the problem.

Keyboard shortcuts

  • None

Normals Face Out

Overview

Normals Face Out will find triangles in an enclosed mesh that are facing inward instead of outward. If the mesh is not enclosed the behavior is undefined.

Before

After

If you have very dark polygon faces or if some polygon faces don't show up in a different rendering engine, it may be because your normals are facing the wrong direction. In these cases, inverting normals will fix the problem.

Keyboard shortcuts

  • None

Hide

Overview

Hide will make faces or vertices of your choice invisible. This can be useful if some faces are blocking your view of the part of the model with which you are working.

You can hide the selected portion of the model or the unselected portion of the model. When you are ready to see the complete model again you can select Unhide all to make the invisible portions visible again.

Hidden model portions cannot be selected. Any commands or tools which operate on selected portions of the model will not modify hidden model objects.

Keyboard shortcuts

  • H - Hide unselected
  • Shift-H - Hide selected
  • Shift+U - Unhide all

Delete

Overview

Delete removes selected vertices, faces, and bone joints. If a vertex is removed, any faces which rely on that vertex will also be deleted. If a face is deleted which shares vertices with other faces, the vertices and unselected faces will not be deleted. If a bone joint is deleted it will delete keyframes for that bone joint and may cause animation problems for children of the deleted joint.

Delete can be used in Animation Mode to delete a skeletal animation keyframe for selected bone joints.

Keyboard shortcuts

  • Delete - Delete selection

Flip

Overview

Flip will move selected vertices and faces so that they face a different direction. You can flip in the X, Y, or Z directions. For example, a Flip X would cause the selected part of the model to change to its mirror image from left to rigth (as viewed from the front or back viewports).

Keyboard shortcuts

  • None

Flatten

Overview

Flatten will move selected vertices so that they share the same coordinate along a specific axis. You can flatten in the X, Y, or Z dimensions. For example, a Flatten X would cause the selected vertices to all have the same X coordinate.

Keyboard shortcuts

  • None

Duplicate

Overview

Duplicate creates a copy of the current selection. The old selection is unselected and the new faces will be selected for further manipulation. This is similar to a combined Copy/Paste action.

Keyboard shortcuts

  • None

Extrude

Overview

Extrude takes faces that you have selected and extends them in a direction you specify. When those faces are extended, each edge becomes another face which is connected to the faces' original locations.

There is also an Extrude Tool.

Use the X, Y, and Z text entry boxes to specify how far faces should be offset from their current location. If the "Make Back Faces" option is checked new polygons will be created where the old ones were, but facing the opposite direction (the extruded area will be completely enclosed by the extrusion).

Keyboard shortcuts

  • Insert

Invert Selection

Overview

Invert Selection will select unselected portions of the model, and unselect selected portions of the model according to the current selection mode.

If you are in group selection mode, ungrouped faces are ignored and will never be selected.

Keyboard shortcuts

  • None

mm3d-master/doc/html/olh_commands.page000066400000000000000000000000701324021725400202160ustar00rootroot00000000000000PAGE_TITLE=Geometry Menu PAGE_CONTENT=3D Model Introduciton

The links below provide details about the purpose of different parts of a 3D model and how to manipulate them.

mm3d-master/doc/html/olh_detailsindex.page000066400000000000000000000001041324021725400210700ustar00rootroot00000000000000PAGE_TITLE=3D Model Introduction PAGE_CONTENT=Contents

Contributing

Contributions to Misfit Model 3D are encouraged. There are several ways (both coding and non-coding) that you can help this project continue. The easiest thing is simply to send me an encouraging email. Bug reports and feature requests are also appreciated.

Source code patches for bugs or new features are also welcome. In the case of patches, there are a few guidelines to follow which will help expedite the integration process.

  • Follow the coding style in the rest of the project.
  • Make a patch from the latest version. If your patch is a bug fix for the stable version, your patch should be against the most recent stable version. If your patch is a new feature or a bug fix for the development version, it should be against the SVN repository or the most recent development version.
  • Contact me before starting a complex feature. I may be close to finishing a similar feature myself, or the feature you wish to add may conflict with Misfit Model 3D's design goals. If you are interested in contributing code to Misfit Model 3D, I certainly do not want your efforts to be wasted.

You can also make contributions in the form of plugins. You can create new tools, commands, texture filters, and model filters through the plugin system. I am willing to host quality plugins on the main website, or even consider integration into the core codebase.

Non-coding contributions could come in the form of documentation or artwork; or possibly even in forms I have not considered. If you have the desire and means to contribute, contact me and I will be happy to help you get started.

Plugins

Plugins can be created to add new tools, commands, texture filters and model filters. Currently Misfit development is done in C++. If you have a compelling reason to implement a plugin in another language, contact me and I may be able to arrange C bidings which can be extended to support other languages.

The details of the plugin system may change. The discussion below details the plugin system as of 1.4, but the development source code is always the most up-to-date source of documentation. Check the plugins directory in the misfit model distribution for an example. The ImLib2 Texture plugin contains a documented, non-trivial example.

A Misfit plugin is a dynamic library which contains three required functions and two optional functions, declared as extern "C". Functions marked with a * are optional.

  • plugin_init - Initialize the plugin
  • plugin_uninit - Uninitialize the plugin
  • plugin_mm3d_version - Provide Misfit Model 3D version string the plugin was compiled for
  • plugin_version * - Provide plugin version string
  • plugin_desc * - Provide plugin description string

The contents of the init and uninit functions will depend on what the purpose of the plugin is. In most cases it will register a new tool, command, or filter through the appropriate manager singleton. The version and description functions are optional, but are useful in providing information to the end user about the version and purpose of the plugin. These details can be viewed from the Plugins Window.

The plugin_mm3d_version function should return the VERSION_STRING constant that is defined in version.h.

See the ImLib2 Texture plugin for an introduction to writing a plugin. The example also contains pointers to other files in the codebase which contain classes to derive from and documentation on how to use the manager singletons. The source code for the latest stable or development release is always the authoritative reference. I try to keep documentation in the relevant header files current.

mm3d-master/doc/html/olh_develop.page000066400000000000000000000000651324021725400200570ustar00rootroot00000000000000PAGE_TITLE=Development PAGE_CONTENT=Face Details

Overview

A face is a polygon defined by connecting vertices in 3D space. In Misfit Model 3D, all polygons are triangles. Any geometric shape that is more complex than a triangle is composed of multiple triangles. Faces may be drawn as filled polygons or as wireframes, depending on settings in the View menu.

All faces are one-sided. When a triangle is drawn as a filled polygon, the side that faces the camera is drawn in a light gray color. The side that faces away from the camera is drawn as dark gray.

Some renderers do not draw polygons that face away from the camera (this is known as back-face culling). In Misfit Model 3D, you can enable or disable drawing of polygons that face away from the camera.

A face's "normal" is a line that is perpendicular to the plane of the polygon. This line defines how light reflects off of a polygon, and also helps the renderer determine if the polygon is facing the camera or not. If faces are connected to each other, the normals can be averaged to make the edges where they connect appear smooth. You cannot directly manipulate a face's normal, but you can influence the averaging calculations by assigning faces to a group and then changing the group properties. See the Group Window for details.

Creating a Face

Faces are created implicitly when more complex geometric shapes are created. Select any tool that creates a geometric shape (such as a cube, sphere, or cylinder) and it will create new triangles which combine to form the desired shape.

Other Face Details

To increase the level of detail, one face can be subdivided into four faces using the Subdivide Faces command.

See Also

mm3d-master/doc/html/olh_facedetails.page000066400000000000000000000000721324021725400206630ustar00rootroot00000000000000PAGE_TITLE=Face Details PAGE_CONTENT=Group Details

Overview

A group is a collection of triangles that have been assigned a common name. A group can be part of a mesh, or composed of multiple meshes. Groups may have materials applied to them.

Creating a Group

A group can be created using the Groups Window or the Group Properties panel. To create a group from the Groups Window click the "New" button. To create a group from the Group Properties, select one or more faces and then select <New> from the Group drop-down menu.

Other Group Details

To apply a texture map to a group, you must first create a material. You can do this using the Materials Window. All faces in a group share the same material. A material may be used by more than one group.

To change the way the texture is mapped onto the faces of the group you will need to move the Texture Coordinates Window. Sometimes using a Texture Projection gives you a good starting point for texture coordinate assignment.

See Also

mm3d-master/doc/html/olh_groupdetails.page000066400000000000000000000000741324021725400211230ustar00rootroot00000000000000PAGE_TITLE=Group Details PAGE_CONTENT=Groups Window

The Groups Window is used to add or remove model groups (collections of faces) You may also set which faces are in which groups and assign textures. Select Edit Groups from the Main Window's Materials menu.

The combo box at the top of the window contains the names of all groups in this model. You can select a group name and use the face assignment buttons (Assign As Group and Add To Group) to set which faces belong in this group. You may also use the Select Faces In Group button to select the faces that belong to the group (this will clear any selected vertices and faces) and the Unselect Faces In Group button to unselect (other selected faces and vertices will remain selected).

To add a new group click the New button and enter a name (names do not need to be unique, though duplicate names may be confusing for other people using this model). The name is limited to 31 characters. To remove a group from the model, select the group name in the combo box and click the Delete button. Note that deleting a group in this window does not delete any faces that are in the group. This only deletes the group name. To rename a group click the Rename button.

The Smoothness slider allows you to change how smooth the surface of the polygons of the group appear (this does not change the position of vertices, it only affects the normals used for lighting calculations). A smoothness of 0 will show all the polygons as flat polygons. A smoothness of 100 will make the polygons appear as smooth as possible in viewports with smooth polygon shading enabled.

The Max Angle slider allows you to change specify the maximum angle that will automatically be smoothed. Faces that share an edge at an angle greater than this angle will be drawn as a sharp edge. Faces that share an edge at an angle less than this angle will be drawn as a rounded edge (this does not change the position of vertices, it only affects the normals used for lighting calculations).

To assign a texture to a group, select the group name in the group combo box and select a texture name in the texture combo box. A preview of the texture image will be displayed in the frame below the texture combo box. You can also use the Group Properties panel to assign a material to a group without opening the Groups Window.

Press Ok to keep your changes or press Cancel to ignore any changes.

See Also

mm3d-master/doc/html/olh_groupwin.page000066400000000000000000000000701324021725400202670ustar00rootroot00000000000000PAGE_TITLE=Groups Window PAGE_CONTENT=}~ٳXj5|a{QVVYcEelsBB7. Zi={G~`ժhݦ[c{a پ=h<#$lعs~[w3ى#]dMkB1@!B K!ad֯Ѣy"z/T⯰!>._пlBwQ?`IX|z셽{DŽ#ѳgp^P¦[B|O3!Cn:,WaW[λ=^MTTVbaXtaU!`q)4?k\DqqOƑ#3{oߎ:^(9]j-J̜u>,:l8_ ,ʕm۶ÊW_CNy*3@!SZZ}te pM[lz;#)N:oձxMXb\^IOO@1c,ҥF܉%hڴ)OCƍE.̙3qqqa`̘9 ݻgl6a#Ξ9oi}Mpz* l̙`\ (bħбcG̚5zС0slDG7-_/ [bqI\uUf3ZHcko _`.ǪW뮇 8y$ d=hѢUp\t 6]YY^=~SZvpݵ6/9+ *++Ѿ]k(:G\Ȇ\WҾmHB \\ !͚5CYYImyjuiii8}%%0xM,C$f󓒒p8xG̙= Dž Vb9ޡٳv6̙vZGDDڮ<٣ՕME!+!$еk7|Vg-=zdBaa!ڶm 8v7k?߈-Z:Q2=xoI&@vm_+lsY+QDGBHTIaǎoq%ļys0 v/ԩS8}4O{w}u#<>@^^&NGoKh*DDDO}$YB~Il1rfϚMwy:{qd"6B 3u cK/"=}6 /@^v잽z"{4m>;պ'Bffo5)cc!.{/ys wu'2z;~ܓqۭC-gʔ>{W b< "0Aqm;?~&Lx t:uF0i34[l> ~g=6Z_Vֳzi9QQQXt9.]NHB1@!CL&DQdkB=Ab{? !:B!bB!B B!B(!B1@!B!P B!bB!B B!BZ33olu5d\!CNk։Fqk!~#l5jxY,(@8<~;v*puFHMohH ?)b+.kXi(7;7YYAix&;3tj/#.PUU[ԩhӺ5p֮]D|`4neQq1vf-=GbM8,sx7BwTUU5k=j$?& X9j4 ˲ٝO&IB!@f-ҥ郯 Gll,͛7O>ҥm,;-d2Amd$&Zrf ͓Эkgol6.]ڎҪ9Gp lB!@T'O#337o=܃\cϞ={adffq9-KiD@A$ߓ'OOO/>C!`װo^lظ D㫯sQ PP Guz:AQ]]m˲ ٌC \Fc,t(:N:Rjŋ@k̻#3g!%%MFŗ  BEUU"""??3dYFdd$\Fĺ){ؽ+Cߌn];c V;JJNa𠛐ĄXt#Q  B!@`@ee%dYFvy[ڶm YQQQ2Y\xR:ww] Z_#4k8~$Kp,8BA@(Zp^L&NP <$ h*ed:u(..ƳN8a<3ͫGyO}.E%k\l HJé̉AR~/DKX:MŁz<]J ]7uP-SUU|];cVg& X9j4 ru:]mAV|NQq 9A6;ߙ<] oEFU*>\!!Z`-ҥQSNףo߾$ ۶}oAc2,X+_Cqq1ڶmN:⭑J̜u>,:l8_Ee F _wgFE],;ٝ( Ghvf&F#o$Yqd1233!dYb޽{q9%wk?Y~>ÆaʔgxB?^`gN.h+^E jD$չsފO{YYY#uőlvn[h#G:=*鐞~+@LLבɄ,DBBAqle||v!Ν#YsE(Juu#7p對FGC گtH3Q`'iۆ*^ad6CGy `@YiEI~htll, Ю];gGEBBhm۶cǎ!֦~%B1@|eplj Նl/)fc( Z$55{drl6#??]e8=f?aF4̛2RRRqx!O{{ÞCbQ=kKAL"NepO{" ^N"IT(N[]?_FbbrssѧO#vڅga4.w݉S=ދ{ޫ)aƌӻ'$Iưa0u P @ K΀YX;vGeq{w6|n΀Zƒ54h֬$!33Ӯm6{nxFT,5g̘3f9=N2d?** K.ҥ˽*@ l&1(&}F,8F#mSZe:V˄GJwNfkMYʱQ̺{ w͵ڱ`cu\iiiDEE% ")9FфCK/Gvwm]po_9|P:3APUU ?^hԨ!Wڵk~*u=(ڶICI!ظqצt:b1LHN j㬎'Zٙ5#^SVD њҪ%&N;7p& UK\pe9ǏC-3'?{#g ^W!઎$ڍ +P3 _54.F+._ ްut }^A]t¶m_Ce|].&M  0v=캯bzWqu'ŋMN7V[HJ9 RвEFs.^3ѱC;mWW,wYGrR ڴNEL*++?BF.hǁ)Z2x"i!Kߕ P\H;qd1233!dYb޽{qk#t%K((8 : :.'d2al޴}=JJJpk\Xa={džPx?C˃?СC̙=zeKq!lظ }N qx!9(..ƢEcǷX:a 6 S|(ڶIcÉ'윽+z=f͚͑sᓵk86za20cL$&&Z?WLof=gǜsf͚aΜynGk0s$''#)) sǿ?ؗ,DV)¸qq8@ ƱsHa{ Ɖ=[NO6z4UUU 22UUUNb$ %%%xxbcXFudBjj*Az$%%[Ĝٳ~\P7 qicIRtUg٘3gNkjp\sn>~{ߏ+TxvtcW=!e D8\CE$''^5sEDFFJph۶-رcwUp=xoI&@vѬY3]vn˪ytt6ڴ)bIjd;dv`5e[K{*P<ZسgՑ;l6#??]e8=摇c@[?tѺSVbܸ񨨨/]3=%,[*DQi/⮻ (}{._ BDD0ozƌӦ%eĢE 1w|Eu9 g̀q2^wҞp9 (nm7[Hj'_oFbbrss!IӜ]v!ysDGG;-k`Wо]k~/Vu+ aMh6:=z"2гW/|@dtMgZ¸'[e;/ZAzZ+}םnϠm4FdtduLbЧwOꙁXL#$0B-,)͑X𤇫D|*Qrw!w=١d B\1hY$IBff]l6c!=|]C9߽{gc>a'_97^GVֳzҲW;|>{l/ <#** K.ҥ^#{,E1@T{2 Way, kgiOiB< Ba00zlݺ+WDZZ"##QQQHJnѣ`0@ h4"[B@~OCG'?We¸.t$I(hܸ1sΡ(дiSk=!q$ 14.3Tn@ oT$['/"]bw 'R3'!|}O !̱ as BZ{:tB(¼rှ8"G?XQ 7 0Hl_Z=P7G .GDHF*֭[pIiQQQ8_qk׮ABB"ny07n첨.u[dB8VX^{ę}Jbxhsw1Zzj`l1ų]Y ]>R?Gk>D׮1zH;h25~F`0\^dҮsb_Qq oLm{dA8F?V:sXAԎJF:FIikJm-ߐ@=g-ҥQp}$Iضk~0Gmۋ^`!V| h۶V:uL&$'}%/իPYYCnRD5ib-s"GٳfOi/;Tt$$-Y>JWDQ?Fbbrss!IS1k.$7ohU"n?|)dfQ#Ҫ9=8oa3btʛ4m݈]>Lyqqӻ'z@ll,N}¨7fWG5 (7 bΝYFv؁?č7tX!ޱeX^GVֳ8r7I|5jI}?D)|[}Ͻ.5j4rrrQT\;wa!Vݕg00oKœriEEEa/aū#22RS j0v;ǡTZtNJ;C鼉Z ='O`ʕX~=mۆ?ʕ+qT FʄCbg%f%uxX5`(E|Hxay޸qc :Fqdq 1O:t8Њג?/b7)fT8}8("ѵk7]vCLLB1&;"G+Qo߫8 F Bֱk9yc-!b.^/_㯨E !bU 3DG !D3=ȗsm`;x B@;}W`El #@ oBɱB hD j8`9X5H P myΎbt )!bx TT@zA ^)"!bhuPhVF$!@:g@&:]Ը&w=o:poZiwy A DDZz:eH;ɕsNC(y)|M"Q(-fB ;5;S nvBRT bN/3Fj pc [t I s-Ba2rrpAch>>P Ehha߄kbgFB&(#Ճ_qd7:%\6|j_bWG$đeؽ yy"Y,IDM DY @2b@2\t ɀ$DQ,C- DEdYdj? eQ!/EfA(f(CȲ Q!d@My)̒Q z0R2  C2$3` R ^P{3dj΄<Gmtf&:Q  CQH&Es~K3I^Y (Y C,:= @ d 5(@H0CۯOCNDh¾L{;lvj9F*XFAۯ,uP]O1؍W~Ltd{*אs1Ymjo?Fͮݻpa? PEvHkԵue_}j_m?9ls!.O iye9+>oEq\-Ō}nﰺ ȂP6Yrt"n/ ! pP~BԼ_P)rXgc4YW0D;7nlJAt ޖȬ{F|/ߗS{9i *b LVjiI`[, /[6a66v#ae* wMBI}NOEDr`|ν| q|q[CrRz 6؝g2Ω@kUb~} {W\t&b FN:npKcR!Q!6رeرs7~0N}{W&1{~ɓ'!;{&~0^~L}Y۷}&;*潸tw w:9ijc{Xz|qҞ^o&"ږ6rx4n{V[?o.x RZc}ΕCe4ONdB$7sZǫ+#kʳ?` )>_{N ګHMiƣʺ?UsE6ɲ*̜ۣ]tbGʲ5~{QF㣏@$$R tObFM*-Ez,]G:Q}{1<Ȳ8ZPN\|ZǠAg1(b]&JN`W]$2EߡCX~#rv}NzdO?[{#GbÆqE&R$Gb7KԁΝxk#OJ[@YY)siO'[_cljMD^ C%4hP3N'BQQQZT0,7_$I1c&3g^ YY/$>Z!f̜V̙+-_}hٲqb˗!If&3'O'v{11,@bb"-6bb'=a_TT[oV-E$t5jl#no(++QQM߭ZӧO;ǕM,ɓveY"J5XscG>^$8f&oA}_c8KND7VDX8z$#//'=m|u<ēxe+رc.^999Xe;z ̚9'OBII fwWj]w߃Qxee嘑O>YaÆchA!FO׭B:}ϜN>GB%*=@V"4Kׯ7؏+7n{!ILGΦ֭[oA>HLLTl{ ^Ngw֮8$P8PtjC^2#mJԍ r0[p-8+5]uUCƏ:'bĉv\: 2 vZp~I2׎ppo\}՘1sf̜屽7o~𾙙Ŧ~g 3w`Pr&J'T!5vAr" ND_(Oሌ_JȑGe[02B \k ]G WBh?tnJ9˶;NK+Γ۔8Ptn(K C_ ys{hah!8q=p8,B_Լܸ)ٔ&rha|xm1a|CBZ B(W(x5?_SQ]^أv,_:z}Dƒ֭0` ,ۿAZz:@Őc͆X|O2B߾uFQ}JlMPEۯ6QLZzޡVv5:s=mOlנ:*lw$EdI#~1P #z8s6. u_z3PfwRe)א΅@ :2_gTrc,BMqMt }ެX;'P hٹn{d`zY>(6qe,R3P_ ,9%#>뎉c TWbdqQ ٷw/@(TJȴf=' dYFZz bbhÁ- @5vQݺMlB1Z=@-陵C5__l$n Wc2nݿquV'^1TjPJㅅxGѶMZHm ƍ-ZbgN.~%?"VnP[r=zD 4kQP `/h_,c |M ܻ{L4 0 0` _/]ڎҪ9Gp9e;ŋ93;C6ixurl❾HNGuu5Z4OsH>~/HOKAI1O_nތyru-fv9SA֩hBeeU}lUv!uAvf2'RT8믿KQPp@z:κŊeطo/6l܄Wc|(ڶIcÉ'W>f̜T4m_7|n/Ic?\̞44k s4l;m6pÍBtt N}۷os[[^uN:Rjŋ qNl_O0s$''#)) sǿ?>W*i`7X )23k[sW9)*j?r㝖]^wmU]|m'G8|pڀٗKC$VaEE'0xM,C$r%Ǟ,.FJjձ[?bp&>%VШ՘3wvEtNBM8skqU+[m:Jג4]CqP8%,8z8wM\'e*Z1Q˵72ۻYBJ ("99ϿiN,|zhRpulRR2 Ѯ];U}K/&M۵QT;[{w]Y_㙬I^"!1h۶-رcsz<4b.G8<' <m|M ax"Ξ=:Zwx~s(((arw#1m 8^Xs1mڋ}QQQh*DDDO}ή>wEq.MQ v2@9HmS',"ZGF77'N=jRZ5Ǹ'Cج)Ϣm4FdtdqOm(#~?oZDFv]ѿ>Ԕ={&VxiTSqqӻ'z@ll,N}鵸ϝ޴] f-3?lҤ/ouVso/P=UW6Y/eYFdjIo88M(-->Ń=LCBF0^umWP>F!F&xMGעЪƮzz=h}wmM@H@ Wεp1.aL#a!p$2 sᨲv$o{,Cc.A d$AE@k6A$e" "rMOP $f:@LE= |2$H!Bue T X!"jDAd{$C$C} IYWEHYPSlt:Y DQf@SDZdȢ\S^d̐!Zjϒ` ]͙ Xm_N,d6C'!Bd $״u`oi&I!Kd%KDdH%@$QlfeH fW}@(%ϝC tug}Z(ם $/ vÇ1~8&ż~S p-Pgc]էY*z#HwO crĆ$ի݊ hDߎ>ƙ IDAT?$Wǩug+Lhi ė%eYˍҭ&$f_=`$y[Xj@hy02耒c+ȃm^'5!ܸy) P ii{SNTkۻO{:8nm VyjSs|t:m_&; V@DLr${B̓mVlW`; hT(PqJ;—5j@(IX+maL&3ѫW/mNa{IhS$IXĈdAE+f._T@R pLԜXUuP=ZBQ r@%Iܹ((-;0>|=h#"€عs':tjNٹ$!i$UzɑU{b hh_][$į|gQ\?1.^dK$ ˖.3YS-JK`0УGOt(d2!wn㏸|2ZN!CpU_TT tz=.T]Bf{pU qrdYv{luu5vC Kf왉={bq1$I´i)}5~4hvCD 9QwΧE !+|mgayOy;Z"rP֭S$4ibBMYL9[͛ѩضm5jKP\\yM4_|rs1`@nرcڵM4qf3Ο须+β,=v]8]r<"}v4j˗aE(rڍJI\հuk Pv@ O*]8֙9rF{R?#ˤHΖV*P}{?%3\7 ްT4඼?zcwψ* Q 5Jrj~~4B*zi12@9Qwi%InyrVlT53aɤCJ@hY(Y1gά+r\9Y1tPxoz D6m ***My/㪫ED0p%ܙ/܌#FB$ɲ . ))U0 $5+*/1EDFy)WjOvgۊ-z8+ޔK!@|K 3pLg:V[.^$&&E04nX3\TWcGӦMǙ$ kn=hҲs˓e8<$YpPm﮼ƍܹsΝ;p10(!a;D 5mD8@B`B ui ;w]kcǷV&I2 MF\f3"##pL:t~}ADD!}ݺ!!!j8p11͠o$+.Oɱڷ0p uzgw?`$IFë™3g Ik/؄nY2۬m0/!id 3Z" o_pPn&܁oنƍ ڭT|y3JKKz Pznuѳ4DyC;t~NjӉHNN SɣۣGۻ dF4b> W{vn^Qq@wz:B(ŗBJt02P>K}qtQ[\8@B (Aݕ }7HMMC\G,ӫ{^xw>{N;gpnA3b{V6_I#ەm_Xlv=Ka߾j۾#IKO;.~`34P|WZI*$$:{NT=9ZwfD@(~!P 3l#)8xwYmWK7{x P ՝!x8DozτDOH $bHKv1&gp$J\H! fw^w;/|laWvX#lE @  A8X94ߓ&QW @H(q#8/ w@H(!B{M@!P B {YbB# h BH`! zfM6!B1@!$0P BH= D0gB !s@H4{o !B! bB9L $Z9 @H(!B{M@!P B L $Ra!* BUҲWBbgfc !z@!>OѺMۻYBF#)[B|u6ׯcl9 !I5bP B!D30B 8! zg $Z9 @H( ;w@~^:'ع{YeȒ A'@ AA `2 &5NSE:0 % BYtڤo>]hC$@Ϟl ?gTڽ G2믿Ri1ު 2̒(BlU²,QҢ 5 zԔ#D Yt&DQ 8eԔ/$3DQY!HZe/K"!ՈoQ Z. d @1,:=jT A.3D=5Yzd2 dI d PaS$% m`@~dD!ЧO6h߾=VZpZ =c|:t8!Ѱ?n,[>Oܕ+ƞ ,ʔqrc3M@pdy(I@+h.aL4+$bm'AHj^-jjQ '== Lj$׮?_>6mچ=02H>D(H8!BmO}}<}8<.;`/гg&.ZZߏ@HhhyFbB,>m4iР&"._lO?aСhڴ)4ii& :QQQHHH}݇bL&d0|pDGGEx뭷*Bl{pͷpᅦ~(_/y~3  L+>;Vx"A|@`2PQQ/ŋ|26lh{_޽{㡇rZ-['xǎ?<֞Çq@AAv؁ܰk~ 7ѳW/L}n ~1&L|O?=|1/T*?ڭڴi%ў7w.:vZ_}$$#>V\n];#)1$cӦM8''[[od=~ҥcj'ǍCEE.\ŒС=ڶINJ!I2`2f[lۻ8);a@FqF0r " qU$I&&FF+UA(uED<#`ƈ\.DNTY]==COxc.jzTVXƝӆƎ],aby?m4ԨZ3f}+~tJ{Νe˖Y9sh4izG) p{]rmV0t>=أ:a ~Zrٓ0ؗBQpa߾+WB?ɏL&|[z/ianuwޱɤLu'ޟZZ?_|IYV;0 }eb>ؼE[z~: 'J-[BI˖EGt?B'^\>Y0Mp䑈>ϩRÆ ܹsH$'N_x\x\׹빾痖f/]TzW_}U;wԀԣG}[Ҟ={2~ I}\ 2T߸RϚ.af{K[mPOqLGGqf̸M/*N[Mq~kDNեKm߾]wV޽u?ϟ9.ukj4kl=bk}O=Ko~+͜5[:#5klӟ%H$bmK-=SJRJz_K)Ipގ]wvh֭ڳgz)˚1cޫ ZZp~y/+Vhz衇I;类N7nTeenᆢߞ_=?YfkeWy͚5[?W\}kۭg=[`Sԧ:eHmّw$Q^2G_ҩcGw{"jkkOv~vǎ{]veD_׵?iڽ{.}Y]tkEe0 mIƎ޾AYYF'xB-2e.2}ڶmhɞ W_}U^z.\!CX]j޼y:cT]]y}u3Vcjݳ5gl=Ygi¹gkuLMӴnڐݞW^YW^YfcF! ?; p0I'?d^}z4wyFJڲ# 8PGj{g{z-[>ҠA\wn$RIUU駟g}F3lQPs]۶ԱjmNπFJ27޽$iƌ\G?36m~izVU@ ѷp ^0 '2x{9=$I_~9F^x5zjȑkG@ ~fӆ6nܨ[n6vٍ7@ɔ8/J[ϟ=.m߾C;w]wԅ^d췿{I.]fj˖-ڳ'YfZu~6m䘣l.կKSK$zV7oAavWh͚5J&zuu/:tϟO?Tx\w8T?[kܸqAܞ[oUwV<mݦ?Hsyy[ON7oVtX3z&N2ys9rs=ƍkպh b >YpaB@[pꪌJ@]]ꪼQ uvƍӂ <_`A^l h v gpn\5h a9]o]]&Oɓ40]yրG< /@O u=n~Pȸ! fu @y bo dZ>/ud[0Zh֑-na @<˵7 Q8 W h a: (TLKp~`A ߁B|naBE! 2 ^[ݥЉ+tr4tr\h a W:Vjפ( 9ÄzJa 40 (&p c* tza{Z{bA@V|DJ_ڻtp40(406  wuuuSugC0ת@?G@! gy/A[V1  | S40kP8|P9P8Uh aEXr`!PUCVk@   K40NU pNB@UpNBfPrztsIDATePs0^\o7a:#na @Ӹd Uy5S4pz&S mN@:b5.Y `@U@+P5*A( `A౫֗ytb\"}sJqB<U4i;S͝36@@!E`/^ŋ{>ahO8:A(9Á=8O'4i/^1A&"@GF!E*f0b-UR t`sЙR*A!:n~d3@@8 =9`G жh aC+\oq#}uU!j (T%Zer6]`A(of@ 9 \xe%I~^tw|n: 2Pd A!$ݦmuAGyJ) tKH. 6A@6[x6+j) TPLh aࠣlufJy \ Aq6NM E![0t[XiM8`TB ~|Y뺜jcP3`ޞS nUR% ym\.<ѻ aq`4gh}*--ܣg mU1fJ7TIIJJJԯ_?INtE0 @ب.]Xf?A2qgN X[[k /V0`s`RQWXZh n N[ׯTgk׮aL%%%:ꨣ΂>y!N34.YBaTLuuuA>Ai˗/Ϩ92#o ZӻwoZTJ|I딗glCЩ~U3ԟ_cǎͨ> j9QJJT__.]K.֭vڥv ]p=a*`c L9%0f̘ʕ+>븅cEEԤjIR>}r?[o a}j0 5zlժUZns ={ݻUVV&0Pܬ={hh8@*PA964*d; ga:䓵rJ >\T*#GuJM`_a֭֬Yca`4<:}E lπ3=naBQFŸ́Æ t5 LhTX̪iii9~fa@sS ݂iӛoǎ%EkgπW̏ 鴶nݪzI,ҥ:]vUKKqaʊ+ ~̓v*ܦ gGpV"P<?Əԭ[7D"qA"/A:W8[o-رc2[[9\?kVm[YF:#TQQX,&0Խ{w[#F!O5t* AmPpȓj*$xz^*F"VYp.h4qCsI$J$.D!: <& ?{à3M-D`aA:Vee6oެ~@0cաaktI#;dNu*"K{80`}뱣:0TQQ;s3#N襽{΂ӧO4AvW(8qpIz۹@$xm'V ~P9MhTvҾ}tue*h@`ƍY_j8L J̻z|ULMww,@@`p^lBW [oP_pvg 0OeevVL@ P4h S h/mBlf|g(ȶvz:Πdgy&>*( AP l>O| K ȥ+=ykjM7q}n p ~ _5fDܾvފ\b!J 6&?{.U3z z…kq"\ 2duRb1k1ްaukmٞnؚaq50={o߾Fȥ/@x5y aܶmf9`.@eQ!ڵ5Lge 틳: ^C^{2Z!#eA1vDݚʀ߀9A!Lso_P Sl7v A<͓^^%FL ACCC#0(:ש071 3ĝg(xi 0J@@as~`\)^au+e.G 1MpA{TB6 xa;M L(pP`6:Q@eyV *aTLRw>4gt:mC`^*ba_% ~a 1۫a;@` ipxÁ[0?Lu!*sV! Ng||Y3  ^߭kU„l*a?xS*R*RSS(`;\ZS9fwl>zo8ܾ60gqG&P8  v ::]/ f]^TaJ$Vs2 Ywܡ?*U}m Ͻ0Up~NL&i0_( A~~%x A/YWܪņii~A:^s~;A"M0ӭ ,u a@&P3 ΆA?!o2Fk S3܄ ZZZxs cػwuDVp;ze n7Z^! ߫w9=`o0ዷ߮ƌ sz[ 3!o-{* @EP:m.%%%D"ύD"G\X B|M:qS9~ l*a\/LӢW?LπԀ4YطoΞ97*Ձݻ[A Z#JJJЫR6{eYQȶ*{A + :OôEԤ{f@@ ՊbA>U`.P`_ S} A ]/<&? w兝W 8p ڵѨ}YW~AUlN3 s9aKRjii*86Mx\ͮGnjy ne޽TP`_u ((e4 R)IR4aQa0ߏW@{ fU2PTjiiqQ-Ԥ&"i?a h 8Ág*CtWpN$ kd:;xa2E0v"p~ aCS|N%L&jnn* ڳgN17:>X mw X,08{r ~<[05~4@\ uq7f% 9@0F† s[n g5s="^G^`aBAmz~ @_}?%탮9=B@0vD0T_Z95Ԥ70k8:z:=x}nr ֭0~@A#LQGe XLX,t?VaA-8+îV'k2&ӟgϞt9R)\.߷WY4 aY J?}:@ ;W?zasb38 ݫzq{]0`^g#P`]Woо}ǹО]{$igkB`uάYB0e5H͛*  ]0-߿__Vv>PHz=[555V F}7:{7u*;(J+|К:p0"w~N&.000000000000c_Bş=IENDB`mm3d-master/doc/html/olh_images/screencaps/example_bool_fuse.png000066400000000000000000001100521324021725400253520ustar00rootroot00000000000000PNG  IHDRWbKGD pHYs  tIME Hۮ IDATxyxTE4 &!ʾ+AGYDFe0 +3 *"bŏ-(QDIBn]{oU}:ue<&9 jЁ_{{D3 ܹsxMo>~<3\=/GTTl6ny-^=zcL;{vq8QXb`Qd^ Պ3u]%K]~/Yp@A$܉ S%h֬=Ák[ǡ}FǎaX믿b{@.7ͷ6obAII Gu]n}Kp֢iӦЧw/.1PT\1M M FܟX,TUUc8Ut@{"P))~Pj_n!2.iuI-u!(//GllrhGfCRRpigΔF`X<8@lpH_999x%B !ϝ;Ѧd={H`yGqpN]٨ _8[⋝7.eGsv; Ѿ}{'Lj="|)ZVN&<8 .+z-Z@UU%:vh'zaaaW)22JN)QD! LeZ.ߐ7e 3g?֭[O曃X</({ႧvݳZX0I??D<1q,[O$%%!77׭__\M!88EX,ǹ E^^GPrFK!sZX,,$9R\N믽Jb ӧߕt+Wf`SO"//IIXicݻO~ͨwaΜS> ŊcF:tČIWeƲ%2c)x\O: ÆAUU+hнDZh㮻ܹyu 1jłiҤ Æ)oaڴ>X,pk0sl̜5[zgП;#F܍#x'KM9儆b͚uXfsNQA bXw9}@~U B K!r^}UHDAb *Ԗꫯb„ `„ R)#A@  /^x A$T# 7A  A/WwAb  r8ɓ'B4*%BO1PHCi_fF=y,ii5^&>q88X,GuE!)) aaaXWĀ3`߃gR?fCp=$vPK+9䪫sgN.Amrlr11J%,88Wv,fCO._zקxw;֭ Ǝ 폟xݎll~m3AAA"' <'6G ]Qhd@gN\! sgv? 40`v؁kky^rz ._ `p8nO1h`F8PY;GL8Γ ~I3srO%%۷/v؁{٨_{۶mC߾}Qt$Ejjf! ǹ¬Yq,7[?ن#?qM78|;ls ĊdA~4l8@9t26E#6&7p#1@@h- !Q2ޟs[DB`%((UUUy:tXf}yUb1PSSyyu]tkʕ7ok!<"d1N*AQq)N!6M $Hԏѿw\o8gp,7vsO<8C^^%=BxcFTUUsy ̘> ~m⡇&≹ӧGb})A :&Q`疚&bF]h/ي]C!66ٸ;yf޽;yyؿ?[*g@gVŽ>C6tzqnL@Rbk,]o@@@|۷ƎĄV2 OBmJd8n,"ާB-o8 <C X,y{G~ر=N/ߣGOoM41cb̘^s59k6fΚMB 1b}"m# ;;wfG6m*#.Ǝ'/@ L6BA &H+j* *cٙGC}8XVb8< Q]]-[t-#~wB9A $ ȰhB{{W"hz\6xu};Aw#oZ&@$|h2Iy  LswJT*zMVG e>@ 1@% !)ߌ3,s," iz H XgB]Txj,#zgfd\FfOIAbBA >X ^@JR P 1ïFHlE^B@iA$H,(BF_*Jݯ\Xc=%1AF^H(5$& RmP  1@(,ߗA`1jDfF+1A$K5f3E^/Rc}}{j$NAb0  QqD(Q f.4J(WD$O7Jxa(`nhzD #ăڲ PXSKdO4`,S)j<4=P Qo< JW)W}e%#x# eoC!#_\=@oO#ZAABPO v)Q#_p)A8A x1"5 `Z(Uy儂XؤɬX $%%!,,BAbhY-232tBJо K *V9"'>/l\jD=S+ع3 O]۶ Eee9l9X~{ %ˊo3l+"b >.%2'"Εa8P(5-MFu+ d8BYꖪW<zpRwЭ[36?v=f,$EV8涜.=GH=R+py)j3&WT(]!@ܙ]oD=l6 0]ވ]v+ݻ"&:<99]]p%$& YT`tܹrF\FJr}&bc &)) rsa/ݎ<$$$5f_h|?Á~+O 4ݎ=K,Bii)Μ9#G2E Z%Ɛu+e wujua1zlzq  Cllqطo[*w1u:u?3[b]ѱS'<<ii#2* F=sg 9@ 3J'l4_\zl7'@ o8cp8~pG;#[7Xh -Z"zNY+=S&x<44k֬Ú5TE j\>Դ4S;v.K^'QL W,U}aqع3 7nD6m*#.Ǝ'phb~Sqz%j]jT1'{4-V 9 @:=N*4Fzx Shr<J?;qogI>98jE`` ϣ ՈA^}вeK@6W& ۘsW@IdFtt;b'3p7VaaaqPZ<RYvdm\)܈Հ{ߗ J*=V @#k8)Hj#v>p7rkմILh 6;eAz@~,qāe5BuէG=}M(  -bPݭtgB鎽2S;'/&@XroBl@ <  =%yY6Q+XGJB-ۓzxgYSK@ ӶR{l2b2zL]xXu&: ˈuU{PQB@ɪ9FfFkvZ*[?2326Rm ) b-+_.f=,y ŖP;:bsϢF <1 ZgfdHfc5lr#Z S$kYNUS-bBޟCs' գbQXGB '@G@$c5Ej%A#g][2'f厳… e`G%[/{s3  %tY K ʨ%N@G@@%b 1@H2QF,e.c1RJϻ|%{?HN XUc nYI{!5L#ޫ>XV`$0" 1Pc3eؼETb1,T^%|+XlF26CUe9ly۶}Kj`Z`ZDL8&!.6 C`۶O%VV67"6&/_n7/oA ,FAɲ:-#c96w@C gw-T#$fRFJ,M!x/ewp-fLr Fӧ#1Zl~m\xQEbB";̛ܼz vHf͚8P0:NĀj0,x $CZ"x'}&&Ĵ,%,2&.;wfkѿ fÀеص 4٘9sbbbnom{ 6&ң =֘1}jjjQ툏FtTG7. cHnx3EUUG{^y%1A9Lb0+rw0BZ)94!xBJuLZ@II1 z@~Pt$EڭVDAA>b u\h=&ncYXi@Qq)l6Nԣon߁3GttKy8z(99JNH5(:u CvAcժg<ڳw|Cœ9$sHv=WN^lW@!#$u/K{c6L#Jr?ɢB @rr2~@_|1b8ڷkɓƩS<6 K,C|V:{a۱hbƺp-"44aa;wjMy K!) """\'サ#>>qqqXl|ǹ|z%)S#GCH` в:,糌x6Q,Qjō#<) Auu$Yǡ[ɓO>uY)v;`\ RlӦ Μ)f!..u 9җ.ANN.^w8gϜA[= E:;wΣ8{ǹ#1@2byj昕zfr]g(5y2ȝCB AA(/;#+ Qfj">>O{ :8!!!򲫌naa!ڷo8q% BOxp<,\W*ZhJtG;"""PXX:Ȗ~XXUmtV: !@Zojn5PR͂Vf5rde^(/b+I'q@H2b8[<4a<4=zDuu5^y%׋x IDATt|7v /lĔ)PYY *f`ႧvݳZX0I?Bhh(бcGQ˗kѴi3˗{3n?VgEHhVZeV01j,]b`'qȑiP̀KW}z 6ᑛߘ̌ ݄hs?BK=PKXXbc㐝 DcۇV&ZؿêϠcճ;uС}2 ^z_ݧnf-[Ĝ9s]Bai6tGH|UjX6 =#ѳW/3gFv1x٣HK{QQ߯7H̝;< QԒ@yz9=rNxEH\1W/@OKxB`q1u8ؿ?~8#Ǝ17waD{&Mv̕iYlHM9_#ƈw{Ó\ Oc5ka͚u(} t1H\kJ]r\l"JRqކ 6,=BbH&/AAA;vvƍѦM oc!((: 1#~%(W]`[`IòFx(V'$6FBgƽ@ >ϟGAA>e˖{p ?jmoYBkKz?z:seQʻB?nFj",, ݺuǀѭ[w H K+W=eb@D0tZ=+j=j =A$+AвYY܋(osRA$  1jI0*t¬B@(AhYڈBAby_(YAf=&6?: 7*Wْ}EY,ˠR!}FL{IQ!/z{pelW]];pt ڵmPTVc˖ 00P8Wv^Z$&‰"XVleRz$ʙ"Cn$)4.fXd#bP:/#Z=WNwЭ[38vdggc;oc L5k js0n(dnfr/KMH}Z mfFh&V$-l8_N ;е߿?VY`͆8.X,rvƍ8y;_uE.]ݎh@2(YMą 0t؝Xz-B[p/N,ęؾSX 3ga [^UUV|y1{v*xL}qѮ_8,‡[90r=Xi?BшR@EIf'b^FQʀ+M$%ᤢ%%3z, x^8&_~X~=.lFػg>!cΜT|N">.' Ghh ^}eXY&ENa}Z1QZ ,Iਬkrm.4b} YG,Ǎ^bO SQkI?ɒBiܒob3`ϧW"&&SL5^ÛomBbb, |jev;-ZXi!!!] 6-}$%bAzr{n{xX,,[G,` z{&ČCoR2:#^IBw_!Q3@q7.6󒯐TWW fCddh)-=!>.1P\TQf\\4ūbHޭ >tKȕw$&%!,~bsܹsHr699gϞa}?]=?k!03^rW GB`TUU QYY%@`9ϝd8“8yEťA{Bu&~8r+Wf`޼820kO8('1@:gI2gyOݮ#`R@ :WK:bK9h|$%%Xn.vCBB"g@PyCQPPŌ$˜1}K\ƍB?_l{F%PZZ3g`'qȑLObPe(5OnV!4"AP{cuApcc㐝 D}ߪt L: ÆAtS>}aQHLh)AJ2ovL$%ҥ~GfΚc[ѳG7KϽzOܹ3@2G/F 6# KZF֨)CGg>v޽pzB(+ѱsYfCj\s59k6}{N]?{dcƌ޽(*.=2dra/8lb͚u+߰  aa?Z],YYă!`q`j!0kD cǡt)6n܈[b׮]غlܸ%K1v8xqBb fBH ffd03FMi[`h8rAj\{`` 1cXpQ15/>| @}enŰ2b3;)I٬f#tPM"1?nV+Э[w 0ݺuGxxUY Ā ?J3b 鋕%==E6'@Q}.]<ɥ-6%tRFG fe}$p) &VY^FN=Qc兯@AbcͺcRc6-[CVB_O2Ah@ȭWBXkdTAz|9{ԬR!$Ax*# ,hW@f'p%54y 1Pz]/T(@(Vޣb_yVed 1Ѐ=Ns+1B%@ljAH|P:K9jLHAb Ko!`(ןj6p"M^Sr,hB~x. F3Pj'VkgKA$t2*,n^,b@A 1'bcN6оf'ڶk_{:P믽ɞg$*r4RXIe̺232*QڥjTo| 8NJD!1`cto%b#,͆ӈ{JkV]Ba6v(]&I `a'4hc4(*4/DQj7iQ >@ԒB%bFC!qR#<̪K9zD9AQކI,@խ!ш52@ψQHQ H Q;y單%%Hu|.fm0ˆj<%oEkCѾq meeeGz؈z&>!^/6ڤZ{5?tFyk]r}(iPM>Rg$mbH%g5 Bc;v̌ y9o۹݉-T3 X3RRx6jy]fFhX;i11mCc6m;A8ٰyF^n.48p3z?iB?B(2]n:HWKXDYuygR^RbĀۆXH y [@FڍQj$*HЫ n4+PJuOFj(L}2I _l ]漽,Ri2о؏>ِ ]pղE0jk/ᰣ2:8vyꕘ`1$RiڕQ fO_Haq_0A$IDLt$ [2][Ss Qt/I8?"ЧO/|'ιb,,Z`XXxILZVpłxR? 8#0N“ŚV}v;4iC{Ԏujֽ.c+ wEmD/#fСo0㱙F``  ouŋXu֭bp|xGvALthϮ_Դ9tM  A7!mܳb`sCRⵘ1}]Z1yTVVbܩ=$yl~m{(3ᄏj_%d{3k &K,餽Ejkk fj绌ju߸9>>'4 Ċ< aِ_P(9r?p ~;,S_{߇OL)V|un3y]?=O}_BEt>Cwh=۶} lrC(9ר]}0x: >(W23.tSL©S']󟷰`B$$\-B1o<|<&Ml`E@UJ.haѢňCtL4/^-[spflfisxw;Xx ŋ0b>Gq?O|8AmodJb+c󖘙_3U!b1ud" : ׶BVqֵ 㽲2p'$$KLL™3gj())(`ios;zf8& #ph= ݛV1C ;?yuxo]{^/P[! O19_=zė_|1sн{wr ]8qQQQȵ)..Σ,oc*ֳgbח_"u,\:c1}4|s'JKK)xҨ߷Mh\k|kH4B3ؿÚՙ0p`?|u2ez=0ڷGnwIy]H6^3У'/'/^Ν:yO`ɒtcޣgO  E ̜*8kcD۶mqw`@en{k ͆F߫6z7z* (+E.GWE{úhwqrm͚5ŴibڴG:`Ō30c k2N IAʐzN*Lxh"yH`̌ U!T5@$ cxI$q7k٣\#ͨ=fm%fF F/ e$NG;]~̬gsP'^E}ltsa܃ߌ4,b5;S=zpKK/z(Oq/aFff@X=3~ ?E/5g`#ec-: a!#g`%m[[~ߧ /&9Ā#Nj摌Ȉ{JvZ M0Њ bW iYO2KJ$iiAzV= $%όX,8pDA.]zϟ5FZ-;ʕkFcg=5YYhbZ+T54 A$0 jZ ?*fll t " Ā{FINCk֜C7+GSLAF@K 7eșkh%ڮg>Ab0x)+YX6*rc H 4DX;`0zK^5GfnEk 99-3?bQmnԦ=FTX5AOѮ][@c6zG`7*NH~\Ͻ~pVWT'G㑨ŖǟhZAɮ.0bv%F^mr'@8L8&!.6 C`۶OgS/gcc"qevslY:^z_(9}o ~~&02>E#I`ISLFbB";̛ܼz S! jf_~d!z&MMObj뽯Z05}3g!&&AAA馛֦WWWcYRtc0q\8^,sp|tmuhvE#:*\hաuX9ǎ?kQEqql},mݾS qQ?zC]Bmp+o,??3bŲ?~Vs׮YGbgCߡt Dal6NTN_u΄Py IDAT'<?;wFŲuc1klOȏGwvkUϠ)޳Q\\Uj+KߑhN=2GZQR>K kyJ h ~ucĈh߮ &OzNr[Xx вe|j>q)8w6ːHO_hڴ)f_-܊Pcy]if(9}eHHHDFj:On#>>qqqXl| UT[YWj\o@jZv̌ by/wbש?9q.[dλ_ڨ|o]IMKRLreH}1}qqXf8Cii)6<'=| (*:byp'.g9II.4vB 9cŊeŋW\,[gׯ54G>bm?}4NNNٳgDE>;SĀsc-Ę%oKMKsݏ ƜzYY>O{ : }[_$,΍Gaa!:t˽O0|)WѢE TUUcvLɵWx7< NaB"&6h߾=ĉ=_>%_yqg Ry1oجv(YGǽePJ8ABkv?ٍ;w7<ΝsQPPŌ˒;wԨј?N ̟Xhh(6m`ቹ{kIدʳՉ.jȻGbE(--ř3g`{HIa#V\[i匜# 8H@Ak V>ڢW8|;l|E3fo~;fZaG2D,sS}{"22sڪ!''qN%˲P?֑^#b6U^ >9ɕ#}ʰ0 z絢./QQ }6ר]تٌChy uyFZFjM_̄z'Xn>1'G!Ah9!eČ0rzNW1h + )=]$VImg99[^j.F̨3aaYWGkzH_uN$+R#vxjQFNܓi3vx$g Ab.*'X 0s>]`!sf2f0zEͶ @Y%t>5gF8h^Fb) T3@7@H <~A+1B#j5z,Skh=゙^ =?/+@!!pBqAaj\ElAsZs<wuS0Bo*uoA#Pk Nqp}L 1Bdz[)gH^q c @Ch Zڦ8Ph C%/F#U\2B>Rg$m\3?3|JraLK.#&qT=HI#`VG7h ܿrôiSd Ɇ σy 8@}.doçt!rk%x= P唄yh #rGI03?6Ɋ 6Bƀ%ZŘju85UG Ea5jWY&+@I4Xz\,_l;h =2roZ{yi8W1^1*} S_}~+G]]bbcлw_tЁUBEh8 ݎkVcTX,XhGQ* I 4`A eX gflڥ$g@a:/0~VeLk>A֭1iBaIٳ]uuvݍIX>G ZHE+Ig+f=P.׿|@mϑ Fy0Y  U+Wbvj*V=k׬+Lr޽{PVV 7vՊ:dߏ#G~@mm-ڶm!w Af_TT k2,s/5k˗y^˗/c߾aѯ_33q_HMaח_A&MгgO%  )$գCZ~ΤMjb(V[a#2%/!<8{))CХ]vk%%%l?ݎٸݢ{nt -Z\PuOesoܹqY}jj$*\m+@PT]ƀD< 2$R332<%EV=2adK&+KBˬ͝DK3瑞䪘)C<5?|=`ছnFv`XPYY߮yxq<5kʪWo˵سg/>|F y^܋/"..UUp8ʪ8NʋA*6$Y#THZV7x =aW"Q<}3pl{s撇񉍍C֭||Թ ƤIe˖W#&.8C[8pk FYyx=788.\[D ]?t1@!P,W`=YYi&+Imlh .-t]gxDً;ҥZ.qڊ#88A c`[?ݺwGLL,uu[&8 C޽ТE**^?C"X?;:Xի=tq !!A]_Dmm->dݧߋW_7l6v|S=@؈!0:MP=juP B -NπgYgLL4/k&Mp>;v@7"$$6 uv;**.9Xq 7_ ݎʪ*{KNn 4mP[{eLM1.sm6틔!JPeEX,@^=qۭ $$JdkĆo#͛_qM\!1N$7 K UOMVRTեes$-)<(HG+yN*|8]z=5X]#Z*\bjCM%y߃Թ<ϣ₠Be%.TV*yW!1ؼb`cNRU%XU뙩QIYBŒ!@l': @#bAuZ#f,RD?,mC0s狸Qw[<)h Z5"Ĉ-2= Мcz 1@(9ֲAu(3j IJ@xeIB~$1@^+=8OHhW}-d%e332<2jB)ZW <5LB:qx 3!Ad@ ^ ^jH` @+ł%##$f^^)BI :Ǵ$kv ѽ>C4< [?`H=w qͷv#9K$%A7I 99o.\@KmG}rU7oP!X_~]t QᨭE]]!>o^O[@@@, V+._:~ 6  BJJ ~'߶m `DDDGQQK4>|8BBBкuk+ C bE+xfe[o_2ڞϿ@H/`VJ|>'1`qxKL^|M6u?~{g<>x'Oj|ֽ;ڵkK_J@ҥܩZbCPQQq<"[C7"*2m0hFǿ^yuuv33q]Nh*SLAee…J,X0:G_#>.vq1ppm+3:T [,#&b\pEpM41\߽qy0QA%HDn7U@e%*" 0 ,UujN>ݳ0|?ZU]S3|g#Q[[$Ǝ=ÜlM6F"tV\)S}M7݄UVn+ϟ3<%%%ׯn,Y$}y睸qyG2dyv!??Bmm 7⠑ñe⠑1㏱m۶Ӎ='GT۪w+@]q](ݏ>/o^{5j8%|gl27C-{>43jJXP)ueH$2/>Fou.]q8,YQGgoG^%7 N`C׮]qF2 _4if͚jTWWc̙8SbEEEw ,رc-ZJ :=z\m۶g |t8?~C_|f4x۞:B vt/n!M7M_ S !V}qq1***PUU_hn}>^p>ngy =_{?gàA~V^Kv.>v{>3 7UVa^TYy/@k.$ xlقp}SN ‚ b]%?#x㍘7o^ܦM˗/뺘:u**<3Fظ袋;,O=c=>\t%o} g@JM["'b-:u1c'O>~W /Ć P^^'c-Z?=<֭f̘}}3믷f 2Gytytyh.&x"N=d= ʕ+kYp.\ǎ`!)`(\}GvzG)%-\SN}ee0l0ukѻOz¼^_^PVÇn x^ %%=0~7O 'L@II2>? cU^Q~}KQ^Qi} XH~ѽ{wM7݄m?O2e }Y;6[p\ 6[wu1/<8;o):,$I?1c4{$^h`[n_/zj\{5Z,3g&/@*d>TTlBee%6ugEwq ۶Uo ___9?gy?!>]@(7l½_O?T _}.2s9#G̙3uVTWWȑ#&~ٳ1uT831uTTUUӦMĉ>zܹ . 㭷⭷O?ya .q IDAT3/֬YS xX@H {Qb+2͑'+ _5  {<Ltv؁'k _+G3v?j̘q8}"<~?g9gaΝzmYy7Rc trb583q%`ʕ(--Ź瞋_O<n̜9RJuQxcSL8#"Bb())OSCݻqꩧbܹȧ_߾зoO=+R?|t?ߡt_@֎uMוml+x˯Ñd3翈s^>y.x%O<0ރTUU'%vi;v4mǕW\;g}6{983qS,?)BOBR@K/# BtiF'z OP[[I&aڵܩSjn x.aL Z l@pU\M0h`̙3^{ ֮]5Ea I\5ki#)}.TD!sm>yh.*+7ag}bls%Iq:8!_DK#F#r6x<رc'B3ESE 0dPDҮqkMͫ@ I Yh]:wFSᐡC1nxDΜ`o INk# x O'AwQC8O 'f4jr xEl ]{իy"?#ŋW_~*ǣ5c!B)X<:xx!J, $,:`Bi&+WPa![nK! VBH'y!\5rTe!3@!:t0zb)0gBZB0&zmB!:J* !ᲀ  !ttgPMB!cCgBZ BW#!?\:ұa! S@!tl BH+BRj$BBgB:6, $ѝB6y ! Bi%X@H ^ZpY@H BHdžbB:3BR&O!ұ3@! I«BZ.  BذP BHGwX@H ) B:6t!`!)Tx5BHke!3@!B I^<BHdž!, $ FBi, $t!cBB1@!`!)kB VPH!i j񓧟ΓBHb4YPNdSPB踮* }‚b4!Q9 !,(ٻ8B`!лW ihP ()\X@H(HNlV Z p / hC P  it?p $WRFYCq@!baiA@JI#PRP &Ud  , $i?">N D.qmKPҪP fzpz`r 0Aq@ȞwX@H(Hs]}!pQ@SRB)PW@ƌ0<Ł)$%)))X@H(H\A݀Mjխqݴ`ق9!̓b+L3Wj)!B y(rx ljsB  iQW!p.L#8as"k8 ulWET)߇)!c U H-X -h; ѰAx?x<8s9ĆyzXQ %c՘]X9y2/(f| B1@z Ք1 6 )B`݋ubMmVsd@ v- ܎%5q@H[ۇa k!v\|@t KK }qqBq )ZsR5JRh/ŮqmASA]/5 %\A5vShD*pR9B(Z] t dA5 !DB5'cAy [_{(is!hBAANW A<fA zX‐;vF.pL\Iϋ,s,U Q Ap]x~ B!mv $\rhpvrg CA 4bIdi76BG޷rd4g/TR  @qlz~uu/qPLA=(g!a=}Л4&tgBjo>}M %%߫n+g Z \[Re3Җ`!hG :8Y8xףG 2xQlۖ hEBA0,sP9RJm 8HҖ`!h(1="i8/h gkgk ۬E"JAZؙZV ‚l\sl1EEX@H(:`P" F@srE ln4 K)q% ARmO )Ji  @w8p^ā8g6gHl]Hz|_뢦ħlE>RA@m(h(!s0Sg@JPRUWGk00ʌ2 Գ'Ψ+zoaP/N$A=W! ϫ]Pyp|fS  @; ](!~31@ZWUKާO6nlXHB(@  %\Rʆԃ)\ ƈ /6a!)TK9}j^+N/13 h+ 1ܳg(қe,-|fƍa݀ "+"\h;B H8Rܣ<A7~6"{Flݺ/y>.Kc~X@H1@ 3g Wy=zu+s*E f ND_?q#_0(/O;ZQxR_w]tJ$PJer@i  @lhH ΩPBmŃgn݊{*'t ߰!NNМHa/l9yB( 0ۈV'0?ѐHں5t_A-[2pby96ŃoI,/ٓ**j 턂 hNTy/ !iOP tw 21} %%a Wڶ /[̭[!+zaҖ-xwS++C*Ы<<+*oȾN!Q`w2Df#4G曼HbX`DAm"3 nl 0O0nzeDfmP^k &SQ:j0$%i'!h4'0AdH8Ss N«{c-aP=2U @Zh@|HtmKh|Bڅ3BB1@Lں/"3"zMxo_[VSZІ9@{c`iA#M!bݸ &z*@_7okǖi(o؀w7;\E'WT 8eGǓ8 B1N,dWzZ3iYzS++1q#@zf{ 4+wHxgoۆڠ9FW8q++:N4`rd6"-Ռnl-"<"]H8p ts")ztwq uN,/ǂ~pRyytJ$& 8q3W/xOJԥR]_!b0Zȶ[¿D~@$5;F 8PT#y _:wdfSJyEH~(:.IN&M!b@D{N.Xh nu#i4}Niщ呔A`ꡔA`h8mf 8n Pl;hQTtI&nA2 B( ^tD#Eq#yB`AǔRز2,8MENظ 5`A2Z#>~zDM@H&DDX1y2f!P + Zʙ^n ńR8H!hEPJ.BM2 ]PB@r/.ʼnv B±օ B,1\?辔زk6w6mBQLbё p@BNpBTN7~{f|GB@ lS"d442gXZSV¿?gPqRE7mJ Qk׆jԨ| ")NKKpon\nB1@ h ИY)( Ǯ )DzM[y]qyÇG^m|@ [*|Q1fL^~'t-* yk!b+k|]PX}{\;'V\C2>}/#Q;`M#.0k8B(h vbqtB[vPnt{S aoF !qZ?"~ |)wE󰽦&, $P & at'&dzlPлƉ3U`u3SǪ u MgBB3+  il/cplbb̌_S!ұ?G̀4D04DCHPq谤 X9$w? AB(: O~:*L pI5Zhx(,zqr9_VNO-":S(Ѕr X}l46r{S"e.uAB@ ?Ľ#ZH"Pn*LuW|s(hpѴ&zׄDĭ!)p䓰0y?sеk".@!. _;a}oε,q 9i6p?W\~ Wj LEds ̺O-Y:Cm*'Q?"BBslfѢk8h"@ݷ , Vzk{o:(Qࠡ0CN|?]8p_y;wb,"$P 8 'dǜ|B# I{L􆍆`oʅ–7VzkGIșD @wLQ=Vn L8޹5B1@A P~#Z3.yq i y鴄E3-zd \!j͕3:bV[d!!=4^49gѿ3F[GF@ZD@^/7kliЉ xП7E\d?~[zzpe]wJwBgA{+Ǎ Gr P3`jY_Ӡc qML!À ҈W: d{"UBv"$鍳B1@ P,ˏ;.KLepdlKV* `/). }ZB"p\ǁ+6:va3!!b PB cm]\l`@ As tA`k8&   t.EEH8\ AuQ8YWD9c#6V@4@dZ4}2fz#0 E?nun-^O3@ !ط{w߳'ul_JxMMFl:!:5y FD31BRANh1$hkZroIDAT[o !('#`OYʋ6w 8Gfz6C!:d:f{Ǎv@,;[`0kz Ӛk< P n%gT3(n8!oӚXV`h9aR !b .v)3Fș*ȱXQ5ʷ׶jlL !HҾZڙuRP@jytat3si@|@Ԁ-}Fi]Q&`i S & P .15ZˍQrf >K@39.:߹R^v gQx[Kތ ..@ƱImrql)My/g,JDgBguw@9 q lk[ F" |ԥI3FBPX3@ !o؂m |c\8'$.p#OW@,h? W&(AD蒇Gm&A8-z~ RYYe?6W@~#S.A.qDL u#` 06Ź<QЬȒ@xZf2W@JÀ)BiuqM,֏*tAaqlARx,>ǎJH>k7t_3jB(^R"BiX+"O"ꟲ|ت+@M-,u 7ĊZة6dB1@ OlJmXߡ 9\l:i z ضsf퀯PsKgA2Lw@F@DdߘqwH>_c|OS` sI OgBg̝mӦŻ*XAGiC|#ji,_~ VQ>R/pWB1@ T2Fѵ&ZdQ` f.  d:D $=z n!4Aœ2=zir"2jϖ뷾=sWӐ8,fF-2s@ n?!)XW |՟@ʈH?!hȖ&X' FM$ Ϋr(! h!>|׍c2R@F@c.@@C!e"W@_ؑ}srRgABH{i6ʮPx̉-gq lv\ A_H#&t`;~` t/e!P fag&'-#8 @ oAl Ĥ@z" 2 +0xB: Lajѭ8 j~Lq\+ Dv@J8ق\؉0w@},;J(!Py!tH0UbB="qlyl,QB zr_BIhz7!m0ꡇPL64qN 3Esk彥.,г 4vH ~\J+1c( Pd!4A[wjkQҥKX;ilj"0fKxPRB쁐P\MUHj{6kjPJ>rf ye\E1Rϖ~rlq =;n@y A@3@ڗ;Щ!8ZcqDR}ȠPuTN0 Uq8 ,l &"m- 8b! 탃z(xR)x0^_`s%0eYmPB @ XB(HϚuCW 8H9'H"lT QHk e<ԫB  !bC3ЫkW%=7D@Dmp qJ(dq558`,㯕B(H4s&jԦR( ` TP R 5WB/ԧ !^[„B1@f+Įztn(r]9RB jB`jB@KFb? T յ^S>Bi>h#7܀;vK5z @fTAd}M|ZU !bToD Q 1A$`R ;GΙ}+":Θ2uU $\7k@}_.Ruu^S1?B;_\uJtI(A[ dUO YW|x !b#|0/Gi(pަh(Ԋ}]@ B1@c,|믿>L?=!P v΀I 6S@!P B!bB!B B!B(!B1@!B!P B!bB!B B!B(!B1@!B!P B!bB!B B!B(!B1@!B!ME 4YdIENDB`mm3d-master/doc/html/olh_images/screencaps/example_bool_intersect.png000066400000000000000000000662261324021725400264250ustar00rootroot00000000000000PNG  IHDRWbKGD pHYs  tIME2& IDATxwxTUǿ3Z*t&TYXV]4E^PPt*(DV )&$K J23 sԔ~>ޓy=9GnġD`Pl >x+z1@^^mێo? _݋?twB?RWĶmS~DN`۶mV|Ll,}!nT*s!D4{q'TŌ :̆p8ɞcGq)%%E=P B!m$&:!4$޽{P]]]6:֗F!n0+9{ f͜u7w>1) A޽Ħ͛p 4|<շ8L@q;{O> } Kl3_7サ%%%xQx}U<|||eeeXo߆R 6k֬E˖Z/ŻnAFU^+ŋdB?GPUUbЪU+C@7\TT ^×_|F=8 KΕMq;vºн{M 0gcWE^NGfI{hp{/֬^_N;cEkWѣ_-[k+_p%K!((wu,\o֬Ykװi;t 耱X5?w׬ZƴiϣsXh#Ew6#!8bB( ,4kYMM ڴCFf}<:tJ/b臑@aGq뭷AR!++ ݃3gO Zncׯ_GӦM /--E޷ b #3d_bt]_lpƌ~vp."$$* >W334*bzmH;(Ǹh%5uX חF(㎎Fnn|NN6* @ףp5Μ K/BRRJ "zN<bbbpZɵ7%E2o͹( Ӱ!$VjC=1ncw kt:Ѯ];˗W= {Cm,a<#O?~~~(--AmE7\dS``dR8Z%'(!Lծ7&%՛2\R!ӧsZn>}e˖`˖Lzٯֿ Zo=d8?a3xyl,]QQQHNNƆki;=hڴeK@EJJ*3-5R0\<8jkI[)!sIӧO+>۱jU<:))Ɉ+ѧO_^v>}p߽w#Fk=7B1@iBn݊ǛDN<7JAOA@(!WX[n>}o} ! 7?!bB!Gl}sO 4 Aܓ'Obĉ'NH!@! k˫5`#P;ˀB1@i@r,9} BV !u)$rĄP BH B!D!__ P BdcR犄<خ2aG!4tt1A!sl !pj!!h*\Z};(i3 {AJ2(//j饈kĀ+m{rcҾiuݵB& ;; mcc|u !!,_{gpD`B275َOѽ{Wč毯dN'N`ǧ`8xyyk4ar?!BHRWL@n]пFЭ[>=A-GAјJt:oo߾1`@_m_z2,^ǢUx&Lx|(!~ $ }BRAׯ2^AAAdd@sK"Y3_Œf"9% {~ge$?~^^Xb9_<BBKR#*jK #8p~.<<|DDD">~ nǂ-|z/_F !(//7H%#rrn׭֡yXtFx* 99<^X/bBFA~RIF, @EE|||&v?ApҌ>~xxx? {Cmˢ Gcإ0** N%555HIIA=%#ҥ+~{&M̟*zS /"&66 sfcBrr26_M a!Za8qzhުDbz`!ի{c<"[cذa!pѷo?čȈV4Y <8F!8A`ǎOѷo_~MM ۙgZ9b ~{O|wg=7رq;6͛7__/bBB\8>>())EZZ*[!.nCP B܊ƴ^Z'F"A!٫ZliG!٘${MCؿc'Vj1 )tt1A!slRؘq"B(!B1@!9ưl1!B!bB!ҀP!7XLr%M\8Q'RB1@Zq  bԡw A@ LXc!P  Z+cܵ5E^̹7.g B ]Jk͘9Sq+RiL Jeaa!RSSQ^^OO/DEEAN(sDq[iHYG?HH0[V0p/6*W$$FB& ;; mcc|u !!,_닌h4_aWd|(Hc9Q,--WR%qa!>Q^^v|ݻ"ngp ////rp؊R@'\tkr%Eyt’-A9x0ݺuAor @n]pANeޭ Bpםq&QZ 1}4DEAddkL:Ŋ"1.wgD-صKB\Iaa!2ѷo_T*pC+((( ȡhx8HN#GbΜY]v 23q 8_dfea7l*4 8L@ER/o|{D]Kj "孎 D. 6& @LL 4tXrBBBR0i[b;?ہDxx8T*.]1ƢEKE(H kZ=`i|hT^d3cLzAyy9@R E7iz䳚j|``!q yyy2\krE(DyW,_^$<9kln);">mJQBJJJ$z>00iiih߾T*jHOOGv/_FQJ"b@XVgKBSTؐmFhm2=f3hpT"t:MM RRRнGOk=ò++W1\<#{cbXfT*ϛGR\ix0xJ8SKNa5uK6MZ/܄V08qzb 8~8[\hƌYة(n@1{6EfΜ }zD`` yFH] rɅ+ [(V|Xa ;>^G߾}Mz555HLLog".njx{{cEX`52^[/֮]kTib"!dyzu|<`g:'Ivѽ0cL53fΔڸ2Vꔛ v?mD]8߈{zclڴ AII)R qq$"!bKwB>K>d_5r[8(˼\ȁqۼls;m!5hag/5 c7R9bєqm1zj1b$rg>hٲɌB&uT/Ֆ%ʶ&/_MìWfbv6$4 +CY;yZ VˍHݽl'X:),ݡskg&B#ĩB@bے|go oMRBǞb2J@ .RfR-ցҡ G-K9(!ԁw_d_2lqƘeH cۖZlIIYIE-vC$F{J6W,8:*`:ED#Q`ӡ5ɋB(ÅxX$u0F)!,m=j#BYΉJv\$s\(̧Y@ީ-Ojۚ޻b{(O?[3^}PR;\BuzN)e\79e|XIReZ3$lۨH*!&,%nRB(C{bݚ{J\Zwn3[[V:ta@1okWBH}9Nb=gֱh %;J{v)gDȵ5\,!vsd!gi򽶔/+X6b`OFI#"Ȕ8 R=uKJtZ-׀-'{V,R'!bBfο#[ ݛOSꜭ0^tȖ͇VQ5byc;GB([Л(f.:8JtYuA%Y JE!bͣRҚ#ƼD :CXhemnNNN1$J8}4;ӧOek}QYY NgrbPq-RK*]c%nEFqJ".J;^QTrٳ;w~EdDL:> n9ӦNEdDI´FSHNIܹ!7on"X9|I(J3< ! [3N G'aQl"FL@n]пFЭ[>M Ɯ"#Z!,4yW^5SRRy}DGE`uu~.**`cqq=[ݺ $8w9O̗bQכ'Y3RVVHh! &1RAˉ%BRXXL* t@~qdAݱfj1a- G'opU+9h42IO@fV.> 9]@Νlb=z.\ǟN#;'[c֮]L;~'NYYX {Ǘɩx`H̙3/@ {3y6'ҥ{nlto{іȏ#ĘKR#*jK-wEAAFvm15 -ZVK]nXDt:,Xw}|}}cΜWpa=?K/ETT4d2:j,\ ҥ矛\b*DDD&M3g);Q$( g'?큭^IWy/k8j=b%93G#`ɩK$X^lNGhsD Za8qz8~8[V-+qxc>z/Ʀο [oÆW79}{Bۻe˖5kA(L<Ç 1#~ /[xleeeرzKgפw[SSDv,ˋ8]d\ņ5_oVr!|M6ɝᒣbNI@L)؉Qblڴ AII)RފB9)kQ:NWԹY#6/vIJSutb#̣JlLV#Fii(//GPpzꃖ-[2 q&|˜ lq&I3_P %X#^\q举5W%?JEW`j5Z-w{ {7f-scyJ*V{tFg8:{ʼn[ژB1C=9 \Xɜ{Ke;6n, {w2tx!bG 왧ly%9R3 KךwFB>!bom\j[EWMJfeP,B(H$( [] ajȄ%aRbB1غu֮&(u҈ppԌ [% !bԩȰu3!kbC:骱G;w{ gB(ԉӻW,m#䰜R[=N]pP"!>G۷:>HH0q*Ha|nu|>HɆ3g*;0ߘMznE6%%a#uM +˵TyBI ;Ksm!s.ko6%C `ͳvkR&&'B("!`' O-Gl-BVz]b2!!b#=QK[J &Rd#Gf#7_!P 4YzYsńCgE\Xe (!n,YP:<`k^=\p(`$B1@\u>J)WUQڒTɤBb &/,,ӧqQ>}l$24l|GK 2h0g (i?g3cLsm{ڋ4^T*& ;; mcc|u !!,_b:+++&3h/ f#.Z 'JEΈԧwDr'!J(//g;>E]7vst8qv| ƌB޼ysMHٗϗb V-圽TRT(^;*ڡ40q=EiR*D" cL@n]п8p˖-ùsСC̝;Ç^0Dt&QMq;vºн{C!<,ɖauؾ}JKK1tpY-[j e.^ᄏW{}e˖ %9!xatOI&啔W`ǧZ_| ^.j_xX碢B,X 0QXl|}}eP #TҳJl&aQy+]Ι3-Uo@ܛBdeebؿ?yTWWC:u ?0v܉C7DAAe#Ǐ_A;lƜ9pAdd <,e˖I;l͟+co%|?AAAY3_’%0d0]ᡨo .`5knLϘk +3ǎZƴic7h'SΦ$ KNhMU=vk7JrDڒ3`N[:34<.]JAlL T*/_nš,_Æ CLL 4Q1`tXrBBBR0i[&`l?x}lh;"#R04tX`!BCC QPHǯZVT?g;v!*** K,v~;w}pT*,]cF?lJ gk5rG練2.QXx%GK:22@)//7ܹs7.C\Wg 48moooTWWt199<^#4$]ň 2M)nǏaУ{WʻȨş"B>etoLL ]UbN튕^#6S<"T(֌31n7[DZQZZ Aо}{ڵ ())L 4 (8__ĕYAvN}]vlogaժxzE ==]}ƟkZ{/_ EO(\W䯒޸ϔۭ qb-Kmmru-bH"** $'CaΜ9/ ^DDD* H]닔'Lx/ϙ4@rr2M"Y洩Sŋ3+oܸ1o+B̛7W>Gŋ ''?o.5Jz'F΀"RN͑DFGwvq_Z-BCp :;v@Ϟ==zO?ߏDjVS0|0y۷ƎFdD+L,"Y=އg1QxBlذѐ@(W_B0h=y{wKg\̙zO Ĝ902`'PNJY0NFvk{rЎWi$E1fР!رz 4C PTǎog".nB& XZvZF0c,͛7__-c0vl²+lʛ"3k׮ڵu p ԐĜ#47H典q͛o>=z}͛7#+;qq$=G\'7%# \?ߕN͑u+qV̤R;#Fblc ^P!(8<#FR*䦙W3`i&ώ ]r?{egkm NWVE=0`@t&B1Ѐv|2 YpvdC> Bv5'l+d7 {r]B={TT@f9rr}pSwػk%B@NJ\[U ]X!P PH:-[{?'ZQpebX) P ܖdAWDߕ#V1Tଝ !b:|Dn?B:6Wl3A!KK9%!}vȳ5Gu%4= E!bD#zQKWr㪄Ί@X!7܉۲gƻںԮ\(rWEWB@HW2< P(ћϑg #^Ķmʆ uoEl۶q c;,o?l~XnxJ..K?k14.eLH]wbD(0BHHq:c^W-몺8%8R("&0sJVvWPrUBgo{l 79K-YUC:SB1&@1-vHt5P#tPd뗛(!j'@Rc>BqL K.ǖOA@hXZzXlL|ʠܽJz h1xMNP6Yg#P/ 18RΈER@9>sb7x0r 7\n7kWq+벥=qij޷:>^4B̎7 {Yؑx)S&~,6n AdjiGm9[k}R~Q W}sv]4cLzﶼ^-o#/RsPUG"uƸ۷ˊ&:KsRvT^l}&{Euy(b NCj/HAC[)К;cWDGs@u* Ķ#veo({Jv$GLsj i/DRF hǭކk 55Dj-פ$~wxzyaih4HMKGLIq}AR4h0N:e⼎'ǾoEbIU[H$&.\}S?!;'*{+++/#c0z|^TTT08jktgW,^8@I6{g˻((F=bpm_CDDW^BPvWC-ZGaa!ZBg(**4,X0cE]&$zXp"##…7!:6mZ#44r ^_BbuF>֖msoQ[]>k˵t=E# q?I 3220lDi֭н[WdffCAAg3)'""P^ddrss-#gSVVIY ~õcFg;w.z:pƪr"]# oZb9&}1\Jå!HasgO{qC=LIOO7 XM&e;I)[]ÇaK/Mp ԩSa!v \*f8Oc/4pqQZ5l޴ :t4'ܹHMM^/ 99/Np)))uL8z?***q1\=7p ,ZYYaM+cHB,x5~.}" 25Mb߃T}R*i;Bitm|m݆5kW#-- <<< ly +W,Xܵz.\ǟN#;'p9=3clK%=<|DDD">~ul,\ ҥ矋%ꓲUI5T !„gcWVNZ^GNN6+FZVCRAz /Ŋ rzZhq ȃ0ɓX|)PVV Sb'[E-d2T*"ۃHiӯFdD+޻T}R*iƂƕ{smې56ZZFxx8^~Ut/{u6]to!L^{ ???CꓳA{4c:P%v._ wШ`'BeM PQQy^tb޼sHII24m sf̪Oɓ'⏋ 骫!Ԗl衇x 77ŃF>T}rv҈7'^Gճ~46m~p~ڴ۷ƎFdD+L,b,kg̜vmaР{ 74y bUFu|DGࡿB^LK'gC?#*5/^ 6F,> B~ѧwObΜWDE>9[mijcRrm i_Co\D4 !BܨBD]M!"p c!9˜P BS!!]gB! #"BD`!adB&Bqs@H(!، HL> ]oZ>ΝWj~No'u{da!؉ _7 % ?(s[pR2DAM9ʊ2xARѹs'xa&mc^^7D`7 ,<oo/_ѣGq-QUS 쬫ϑG^/:T%]!) 8^}R`Ȑ 71ok3gpD"Cy7VO̘9 \?EAA>ѻwotU]ǏٳA߾лOQi׮=v| >t5r j5qmZTWpyL0׫fu|͛7??_ A+ҥ ._nݺ㏋A(.)^Gd)))xED;<qhߡ#Zt55(..g7]9;~JKK1hִ KCrP;!;h!׵zzT*:r塦F;M4;o:t0QUCVD3?:th_~Mx 33w9W\Ν-t^GM_a{^m,xX#@YY9>l&}Ernrt;ɕw9 :~0`j{ غxyy!zFh4zR 5k2C<0$1_qx;Bl۶PT啕!,,wIi}خ}{?RS/aPyhye+iZ||qwcQ]uGÁ1zzEmYkIQy!(>ފة%(/đG ZѮ]{\t ڵEUU[!99]t5L;Tre~+\|ׯW =#itt;ɕ׾}|ͷ(@ii)s&N-$'bOpm^mnݱy;~:: У8Yr7JJJjѫw/r1** G~~>ږ:l(ի~'C={ 3Af͚]۶DXX84i]M/reNη~ĕ+P#<<=< jg7.$W^>}x [4 uTȀBƤ$MVHH@>cҾo߸h@~~>|O==^ڟ~QQh6?xORZjFM?[: /T*| :%-ӳEsxCѠZCqQ *_WTJ7<[pc,6.f%J`df87gk/s7ooo/4mpzԖn'ZEelg_~9ӌ B-؟@X3s]igKfQ\RRk)+@YyMR b޲}2%&ru`48W[ݼlG\y@2-= I R0gB1w.$P7&B(!A~֮@hp5ӻq;:BBUK9@1@!`0ȀwOϷ6LxYG@KoR9rQQѸ;#\@ 4n؆gOo|>DDû()Tb{U*$B+B1@! G$ u6!02@!"ؓ@HHCo7!`@H#0P BB6:Bqo @H݄" #0P BB6:Bqo @H݄" #0P BB6:Bqo @H݄" #0P BB6:Bqo @H݄" #0P BB6:Bqo @H݄" #0 b@q7xl pBqs4lB۱݈mV&{V mb;$1N z1ÜBA)!B-#B3@!"0 | !D@H BL $G@Jr2 M]1T*Uw9΅@=Nԩ@T$&G`ʔI.q7n  BJ l{uB߿? t۶muv)xIֻĞq=7{&7'Od+XO>>jӽ6`򯳹!cO-\p ohj{(Jz7QP_Op c6b@m8/ ]VWCGV3"@C J7oI{(lSҐ"zkNiSO=m5z{ad@oGdb4T*՟=q55|qze%`ߠwXFk⨨@`@KTTTyK?oԥ] "6OrRG_oaذa 3gΈ'w޽{1tPxzz" =\N?ÇZ–-[U@xQVZ-'W;cO࣏>{nq߅R{_H N+7zqCi{x6|K q?ŀ ڣysO?4zK.!-- DŽ D˒? 9s0aajhjj*0~x\rGũSصk'JJJwлO̙=vi/^ĕ+wJܙtm4~1^{b@~ Bn{ヒ׫ !> t[aĉ(.*^/@PRRECh F~~|qQ1:":*׭^/ <,:a! 0\Ѧ~GFUU5_B=O?i!s/ŀh4Øsa֬YFPP^~e?^,wލx-[DXXVXǏ~K,ٳ#э"2T>ˢ_NԱ]Щc; c ~8L$[k {DHr5 ॗ_…)r={js)?N yXfA]o޴&%a7o +W.7_~-.\}S?!;' rz4 Rґ~%p^ǭ_F6m"0zX4o:t1c!JSz(ac=Ƈ!m:`jzM6EVVкuk|}՟\7^{m!BCàR`"{t,^7aM6PTxW0l`,[َOw ""p^2WըNA06QPؾ#N$spӵ9y&R GYY4 jjj k׮ax 4-DDDСC] aOٳ>ƅ pIxxx`Μ9:u*>F#,G`El ,ɿ?cetj{lyqv|>SVՈ0EFF!77 aC mZGkryְ^JC=CD^^pxQ/h:YL0+Ph֬v>۶m34iƍW"33?8&N_ISGرcuVtªU Z IQyt>,˃ gAQI4>i3>թhup˃u1uuުH%j,T$@%J RQBPwg{{fv~]vfgǶߧo~/R?zacƌՌ'{zȣ3w=X,Ҫ+ܤ3L;w|aV*R6󟫾^twjذa=ڪN:)*pʔ)y} _(;_&N K_POvЏ{=ci&\ޡ.yi=/dDe7Z#_׫]7ou] .}|z衇w^۷O>&OT?jnnҥK|S9/Wss٣}鮻YgGv皚Z]z+ꊕSO9眣3,V[l=@Ą x޼yt M?$4ܔ>s }jk3fF+W }bojj͛5c UUU)(h߾}ZFuGkϞ=y立WGhҤɚ4ijkiɓzl2]|źԥ/;C;w@س*;F>j6nнbrJ}ٲeKu({٬-}A_q%gX?30B{ђ%O+ |ӕW]K]]p]x7ug+s󝦀ߋv-}!B$G:a]$ȹr ^8{*ksvڴiZe>Lg}nݪ{iza c$& ["49J]n}ZZխ.֭[}5u׋#z Q6ټe$)IYV[9;mty啎A4z\e_]a!@O=5Z _dY6ٓ Tz]u QAWqa"̟nI'\rX3?)zKꪪdؕO%5['CRֲQi'imkk @݁ l. eB O $d2Jy5kdW|$鈷݀`,jXVe-7k{ @Vօcmp0W_UU:i7 )wUU*Sj̆ rky 2}*Pb-+6n@1]z\u @9̈́MUU_UժJ_$e֦y4 MSU鴪R)UR-)y?MtzgdMՖʐ ֶjn@Y@с nt' OժdzUW4 of0rd, CIJllXꭄQnИUoxUϝ@:R&)6(iΝj>bDϟmO!gޭ +8{ÁoU[  Un(ֶjܐ!op쏃kk;;6A^54wN\~wwܩoRpE!7Y*@8l![ 46j-hGUieS)e>fUcOȳF< ! 2`Y IUZ.lD@1Lտ7x"pGv;aP@{?LS9O#7$;M"3=P*CP8l6/\4 O$I[)}מrJ V{{99nVdMiB1@!B K!>Fuu5v}zDtT8ztm۶ƣ6EFZzhH0?0y lBq[(29 k֮Crr79r^(tMNM5t4h4J(7;29L@!N/(F<IA|m&{CY;oC ūW"((pU\?@EE<0VF&!/X6 R>} _^zcѴiSDFB^DF| s/Na萡Xx) u.{u9@A9m{;֮{ :t`!8OII ~Kwr{V1̤(**½/68{O'v0w|ػgVB&M0g,c٫+ 2Xp1"""hp}0w|tZZK/"㍷j3&c10oH_j'vak z/@HH(z dfΝR Bŀ1!8{܈;* ϟG߾ĉ_ :~͚f׮]CÆ @8)((,6& FIi6aԩS>_~=(T*TTTM8WPI4w&P[SϷc>oed\6uXцJKKѸq?5wBB.\(6/..BARAt:֚?&&d '~󑕕W+ "D2zҥK&6%&& &׆Id)R4l*BQX );va o3ѹs5Zhժ̙3m۶YD0g3Oc9xиqcTTM7=$$MV&ȟȖ  IIN}Vbp'RL2h4k ݺu?axwMzsf5k_ZY3ׇ6=YL6/E||88999&3l,?@Ra2tDO?3 ￷b<K,CnMzݺFyy9 zSL3OM}j)#Bn'hb*,Z8>X77f~\x |?** IL<sF _a5$pA5'A B1@]!`oݺuÛoioAB(!o#`P B!bB7B(!ċr#RBb*3㿕ۗr%80i'|<"*2梲*~'(=yBZRztސg2&1;~!e݋^TVVb׮LG-+Ky!DEEjY!u^+)BbM>2AA@??=B@79PYYO7}2b84?Z-8M|#R`1h48_`~p9b BĽBkJe׮Lt={ķ~>} <<zŽ;гgOtwA,jhL}ĠZpDF޷}Wݫοx555WbyhӺFagPVVʇb e oeee8ݻwǎ;#(++áC#૯BQp,JKKF,.&L2^~9 9yغ+DFh‚~p ! 'z!g8B@@ JK.@n?SAЪU+ GX @UU%&璒@|wx9m|~~~ ömѬm  qAIj6mɚzON5}$f***PXX)S&CO0>mxMk4T1z>m*٘8a<>BA@(\ ::i&tԩ><ؿ?b6܀WoAV@tlrdzͰ`<[ސ@w<)ƍ}8L@A@@!@#6} N} A޽{HI)9ciΝ]ߛ6fX#F`Ĉ6j^z^z U %e$voyymV"P+|iANZ  4/_F^^.*++.]I&~P P zz0vj!!!ܘP P bN&gH(~.K ZUPBBB((((!D^3ू΅Bȇ/IL# B B1@A@(H sP  B!Pu@CPju_4{-q vA`LH!@(WFD7>qx-_"B7 ^+嘬9{kN;}{ooө[{Do B(k뜷l)CPB(H!}Gy40mBAuذ@ap {Sʓ[P PT!77WxC'Y\sr#F!,]cS>Cg"SJ@/*++kW&Σeƕ%ؼqoА`C1u1(P"ɞА`^F1@$&OĜ:@$ Z8)8,G Jn;&!epgjqlc ˎA1"U4#s^gG8*2WPڴMBص+:GϞ=V8^zAa +j%oddڶk׽:։"\\s`_@'0tP,Z"+z;T sd-Qbj~^f np|!wJAУG;R=I[ٹxh`L:YիW|a!ݏ~BHO_PY"G}{4ΖwTsOKK!0OӖͶ7{NYY@f&"X#- B~~~HLLP#ZK-GTTT*ƍ5W٧/ JE`G0BIe"<"`͡:", k;==ݮ.svXz'<q% bPYYi| L^5zh47 5F4p%MLLŋ$E(XsکIIHailKVp,M#V=^S 9iiiDM! x><<yyyhݺ\DEEK A~~>Zj8s   !w\uM !'䚲 S HJ>8 <8th?Z1Zc.ΙKyx=ٳfG:Æsj T*fϚ!CJ.&!`~V)R1`'wTQMB6mju)h{xCѬi4?4mڶԩ L<#ݒ <<Ӧ`dn!-/G][R ,&d{Vq}ǦMCӡ{&=Z߿?87Νs[FlA!cXzCe7* *gK{}]n 7 R!mz׹iv^:i^Ɇ0^_52{Yw=b@JHڕ $$$ ((ELlSb@?8>Wne#f 1/OKTO#hC}JGowzzIsþm-t:j51h`\|yyDDdt&MY^',oYP6:ZũB>_>=B1N^V#$$"ӎS/\ܝO HK ׉Xv!Su4]dVNj⸍W}k,XێxUG Bqanccs#WܭȊJUgkXzؔDBqpHfY#cbpr=[b@BqZXrb:= N}n.՚*=س 2!b ׬6em?OE 6$D-% ZY}~cs,/ t/bpքTeuB1PXґйEql K*Y! :}P:aM,I2`!b-s֗Oγ 98G)G[~ cMĒ5(!!gBr9:( O! #.(tXrrG;!b g{rO/#)a !k` BHNg;bq! ul_{*!b|\=8;h\Cޓ}V"t G0ݱ5qY>zpQݻGEiil Fuu5ZA(B@,U{+~}DU=kg؊b1:@Eus[ng}epkr7o֭[PYYi\4#&:֭_JEшP]]ȈPXp B1|a`o_dzA չotT-ؿ~eW "t'hw&N!C{1q4 >W^Z΋' !>BvNfΜ6~(kNQF&XB F<% iA6W+}\LDq]2ѡC{ٳh4ի:thݻ3`0iKB@@n|Lz&u5qh޼&N*@dD(Z-bc"M_[w "<pi>ސԘ W &&8qg,\0YYYzP[[k847GV۬CϥKLlLLLŋL 7 DMM WXrPֹ$=O:cA :>nv8lˮvݞb+rH! %l (/@XxUghV3^A6-MBPPGVgΜADDը룞y؀ƍmZiGXXѺukeRp6oS!)<Hԓl'W,,o,p֮H"U{@#>>78rK"'';uxQO1cѹsTVVw3Ix 7=t:G:g+X5j̞5}aPFNNڴi#ks54lx QXXŋ3r5kVAPpVXEHcX0.WJY31dP2pcT@jUu'ЯThS8!,9aW96+D= ::N3o>6me<6+6[kN8v(2xp+oкU">]&׉ $w]:w@&M0e4P:o/_r,^Ą8<סҵI/V-[o{ѥsGJc@6m#=B.`))ML,Õ">U퓰xB^GlA(n){@b}cӦн{wmmm-ߏODJHys z=d|]M^3fo|^6FAZM1yJksc `eXducXz=P x@H rO!Wro6gh{w&b#Y{_S Bŀ9+72ryD@anyo IDATvo8Bŀ#P;_Y*a؉B1%Qo01}05)D !0Z-yr:.{~<5)ɥ@N}7,)! wrLNTv''YNoɄ"B\*3㿕W׾OKKCzzEʲ s LNl&xX\U+6y2Rr6 e6mp^]ͮ%;}xo*}Ҿb~_s{;o:[Y}#m>v28~FԤ$MlapfKm[K6SYz~a߶Waŕ8R?ħ>AǎIH19kZ8p>G c5jd^iB}JP gj#3v :x AHq.XMZrXRyYY&䊞ZZFnfϓ:U7W.$]2ѡC{jիt:v>!`V5,{u9@A9m{;֮{ :tDdD(Z-bc"MիWr6n@ZM\`ymÅؾ+,Yٿ#22 /N4hfyxեǨ⥗^'Y/6&e;w|tC ŢKl)Ȁ'lĜ6BRW3Ir 9a@dדU8eee8#JCGXnJKKj32h>|K⭷ԩs.#6&o,-4i9ga%X CDzL2.\KvI*oԩSر[7ƪU7,d1WBٻj'? a c _Jg#bEjވ# ~&2 )K 8y&%,bE?ADB/Ϣ0 hZ,]QQQPT7n<֬^UG<;{|͛CRa+ѷj1wݴ PTXpUO7_ 66* -aĀ8G{R;{qvup62@1 pcf#(({fp DMMM)..B!6&Qhg;k2Laÿ^w?:uL_D.^ "’}Ư_t FMLLŋ$?q+eړitރ'.v)p#D)A@yyBȀ Á?!l!Ξ;b_$įX|%f̘N'0K9sbxW!{u/{IOOW&F߳j V5v]pp0rrrL^=YL6yyylL0j'OUȑO`֬8˗0kL?l,?ŸpfϚ!CJxm3ݎNד9B"LDGt}۴)BBBd KGdğ/{H1 bѯ_e{x߼,um7饗Ѫe+{/tؘX?yTGDgdtKpL6¨#B6KOA= (7}O`Ϟ=ٳ68 {0YJޱ~ZFAZ?5¤^Ƒù"|?xG9bD =bgoVyXd~;߳s:_pp0V^cG(m6ޏ>%Fd)ϕg#:bB}!ۯvTR!!bǝzOE#rDN+#+˰\ P z x˴Jg=@"B1Qg˳$g)A@!^3yKDQqVxH2!--_DB@}05k 6ޯ&O$ܙv2 mHNwBgbGR+3)GE{ :脉+vB>,,RԋI{,BqlQ)|+~7Ge$&G[IQ9;ǚ N+!d' F(s2 #;%@}T볲T\1J?"Իîod\[܂Ňx&p%n|9{h[G~w{{]PrQz,M%MmCNv6H&E ~~4UFSΪ~)qڷ73@.-zrvM;WAu9waXk&b`;!m8a<*++ 5d (rgD-uke xa1"~ :N!I^cu`t@n6D;z*Z6#c=gea;q_e˖@C 7/g -qPT:CQط ? XUyV+&Afj:u ۿމ.{/1lp|6TUU1"3Bδ3Q nF<λ@ii :!mܹ}!fϞиq0f̘_m РmS[!!!7ЍBqr:sCLL ""1o|ߛ!:Wlb O0w|4ơ7_*mZm5Ctt4 stL $9pKBNp7{D31ѷЯ$@tt4VLǡ`wqc w[S4kPXxW][[k$n,(--1yMqqq7Dž Df 8IY{kkkixG 6~ ^1Lkah@lwE_K܏f8" ,GlFY!::SNÝw36MD7:ѹK|wac]ENLޗ-[Μ9:زI>??Z=oދ/bc7`4jňȀzv;<8\ZN~#Bl+ajQ`Ϟ=z/\hӦ|c#̙̓N' ;;/Mzp>(8999V;6.?#w^,[cƌ3Z8\?_b̛;19/զ>Ι3(--9s$CGÑaG`_pj!}9M˳so 8F0LH^wC=u< k?nxtMNSODV-0 {n yqZs.Xh)͛۶1Btդ޹K |zƍ14-^|qZh^=#::Z})}t84a}t6o+9LC޸=!|op2 猆 FP"- rKCƏy??5&N's_~׿zΞ+„:uڛ3lz+ΛmFϟ޷{7`k0DoޛP7F~hAd?.9ɐ_tRŨϲ-N!૎U{+:ܹ+~tpNöl9{"QNg!"sA1KzJsgX_  %L-=#R!^iZZČ"yyr0P!acYMm=qEvhG|Kز.Gtn,go7(W8x;ApYټTYCA>c;]h3M[GBb"ŀB$,wW=LEn\@zvj23qk~zu %g ׷g!>E}RD2 ի7ŀ&v?7ѿRBmbMy RӝCsGfhx.nNAT*{ac١ cGaqlc(m[1 B1@9CGF<.0D(yy5i$&4GLt 苭[t ՈEuu5Z5K,ƻ؀Ki?)r (Ɂl=J0HIBp6p|8$'`C̙zo1ΞG׮hРb_Z?ŀbŒ'fm#GcҤup_z C-46 G?RѲl][^^YfuD$a5ؘHhZD"2"TؘHԠYh5OSO>qMa>s٬O۷޽z :* wPSS#j/aҤHC0qx\r`>kJi;z1\ھ2'ySTX;V#// ~edzc8o KW%_vj:u ;v~Gp&g PPX,j繂:׌4F?w|W)ޮ/Z`>)4i"^~9 9yغ+ ̧݇Đ:),Xc3v|khyО2lh%v55{w{;r0Su=ZXL ڶii"|͚&IXX6&&hݺ,>fs+xиqcTTM떒ekd^N*#*:hժ̙3x bλqE8ܗ < x?$'gϏ¥Ku~{;'|ӧME^^ ;;'-ֵÆ ǬY3p6?/a֬sɱ+hӧM5)[ϖc~eڴSЪe+{/tؘXùq1veį^K/DbBPt伵lگ_cG!5ˑ-ݑsWO՚rLYgsj{ƾq lr ~fU:+z]+C.Y x =.q{DgT'f֦z9k[mMȑ@Hŀ krbw8[1o]Q婨W~ ڬG/ʼnB4Э9{>G'y*N:vꄰlB1@f[إ819! -<'{Я@HձXrbn(A(WmM!> pt )3wb&Ê#qxMgRb#Z^I!F\ +6/j=NKqQus9-|()C8q4$A![0P 0:`1 h-%ESUr{BT萇D` IDATÓ;09ǚͧIwsgޓ#BQur cB sʠ+qdqUÞpĘZ߇l6Lbٳ 8>[R,.P-AHg܏?r |H$~P޽P x -Ks젭'YJ퉻:"haNv63ktlD"?6n)3A`^sę8? %Y)uL^>3br{i[v7qf cA !El>_ xX語'Sm]U6" zQ@ # Hݹ<8vRuuR\kb퇝{)QF(v;RH(E01*PcBF}ϋĨJk;?gJM;ؑv# eeB{&>ȀǒŋB=WG89JX~ :".[ZigJ{_^DFE!9ڴi#NjhZ^^NZZ-yk+"I^,ĜK˵;zK0*P?p>Pp0E LZFIտдY3 <?={NQԥ ms^^{}f(|@Hq*bS7rB &)!~9Q9bfW d=W#m@隣g^\B@@ >) ~~~~:؏?ׯE5j$ZAA~ohp} oikk$'k_}ɓE=ܭVNìYspʫoB ХK) -c|(U{GpVX SNZZ[l G! mʰsNIIwwƭ6µkqPt>;M4_{D뉌ď?mڢq&mm-\Y8x/^³;bШQCL|q֭]  .^*Y}QQQ/▆ aHsvŀ {*6XĜ;#@(m n>D]F@R a=/M:;uPը KpkF{@jN#RF ,< 57~u`;_|jk} ((lgOvݿ<'xᡸZQn{@RAV$J *_OɧD`T\D^pێ"ɉMKI:pWsdcj fg$ pp.P;# `ur9A0AqᮻF-RP^^PT1uN-4Dy:{5ٳ;waá$'k^hTTTP^q:N%)Cj{vWg-U]1+K!@M T%&`KUU󉎎Af\|ŗh{{[h1cG&McI\t:Tt;u88%%'kqEjqeCy/_q`G8Ⱌ#\]#VV rsj:C°g^n187N_h$eQ[[@\X[lE^=R'h[;uBTT4558~8BCài: <)׶n[~j? ~:t} :܂/BS(,u|7{P~mhKw} ` I'kiz]zf:*,pDH0@q61ra:ӧ c())AHH x`7C:uƯĖ/!!!=rgOX:i;GPP 4 jZ] wމ=# jZ-+*D-11ڵE``6hv:JJK%7aD]h4ֽ; [op#g@vAAPT8Wpfy hp`!Fw`#D(PndzzurܗL "+mw_tBׯ_&']*^) I6TUU%[=XV]R\)/Ǖr%e@nP 'A`qg?n-e;\9VN Rq>оad 9}qtWn"qGO;"YLsq̎RUJkc$8>P w<9zڝޡWL[ԯ3`i&"oLI vG.~)]^Nڝa[YlkFK P8@(ܜM@1@yj( spbrFW!E\pX؋3 ƻQ {\ɧIKKCzzb]l=)^W.fyr~F?<[܂z~?]w>#>>}e] x|]x[>{(12^=b;+Z;=6J;F%H$ {z8"Dd)18LPO0d(u5G-%ؐ!!Ҙ-Qa~{̈whJB}лw6"zqג#ıo˱(%z`O(r@H9ZCtG(LH   .1 gzɶݱ5QbmFB fNۑEl 18" 3R6w"U8!!@Wc5pvBB(G6U:̧Z*\W/NDT@H(OF "eY*[JD 0P :aR (!b(PHqllm:zM0P ["°>%@H("/u@H(!BgM@!o 7BT 7O $B0P BH= D&B02@!n D02@!n B0P BH= D&B02@!n D02@!n B0P BH= D&B02@!n D02@!n B0(UI@!QRR_nόbcBH=GSRRV 'h5L $[V 'iѲ%zc:}! J9&t:!bP B!D10BpBqL $JBq#\( B`! #r.9A>bٳp!D0gHNp$߇ׯ x=(Z | = y ={1\@6m-:lco! 0:'"ėPT7{▟?SOʕ+V] HN+V[o4{&Y|TUU!< PSScxI@gȌ??@`` зo_8qby߶m ǹsj"((M6oSKSO>W[+ɦOwy%v*v=\(T ƪ~~j y>Nb]腤hԨ3Ä/_geuأݕt -[(O ̟?mZDh JJJ 4k!N'mлWODGEwwk ׯ\mfMc0nX\|P^yywze&Zj8]:ؘ(hZD!2"p}mMqt U~ׯڵڥ{6ty/ŀh4&1+LHDDD`,e-[ࡇB&MKb߾}{…:u*}Q4n >s*=v(PXX۶ŋ۶B>q1&p= L"$dz8/eKLTc78{<A/O¤I/|e+N< ZmСCر[:t%jU72Z}k֮ƩS8x @ 7/g t:;@VGppc;l!kb0rGvtR8k׮EYYʰj*byoРxdk?ƍCiiD_mahthӦ- AgCL{1>\e!5{n6c6t:CR+FDD$j5t:6lҥKh֬sCtt ""#1w|ߛ }чVߧ>̝;:ݟ[V `DctظC 6tD^+*$EŗN\իWQPPR|G0}t+WbÆ @DD6l؀5kX, GԩS~z7p)УGO̝;/S{͛ǹ-gU9|Gw(O |?5mbЩc y޽GG]%$)WDS"Rj*UڪzzNO]s,jݳv{-تV.,wI$o{I2Lfs' LҒ}Xo)'?/g`8qs㏟}9?g=߾}~ËbۿD/ ߿_K/.792`Yvy/oG GxVfҪUzj%K+Ў;k.}+sF+.LEiÆ jnn%\{ǹ}ժUt˲,͛7O>rc,,o>566ꫯ֮]4sLuwwӃ>X1(+cW?_rueN \<^Ǐʶjx_iΑ]d? )g٬~Z GChZ -*wݺ7uźKtE駟s}[{~H@2 E3Zp cTMe* _`T[[[b i:^݇N< ǥ:m6:ezh Dن_z0#T>\])St7VnG+N&P1~_iM! [gqf5֖͛Kzʚc0V]A!6 z P4Be KR` 办{!' @K~^"6#}i @Ue]A!P帄1.Q 2UB@}o nTDh D2%D! @r4lߛ(Q @ @*Ph a (&FeJB+*PB4T1A*G!.Q 2UB@}o nTDh D2%D! @r4lߛ(Q @ @*Ph a (&FeJB+*PB4"[}`@e i` \(@y`A8<@8 pTA # h aX@h aæ*@8 B G!(  T1AU (Ϡ.*0ㆥK6^[V]+˲ @0Pf Uj>S#Pv( :tvJ?uE!ˡOW5y TaU@@@w0 ~Zh;r@@TǜRx T=V aAX٣r*ѥ06,]\ɎA٣ ^}X`puT^0 0GVpTA=Á;^٩g:*o |EB*,xU 0`s ^B!U܃z:S TP9h a Ǡ A!S T# m>|,CB*8=8ruAb 3IDATUJ0EJA!Z0]`AR( a8* ^@ `J40P%2^9MTS@6̆BⰩPh a ^UBuB+)R440HpQ@AՁU@@+*P̠62 PDԠp40A R + La@7|?gXQ5JL)2rJ*P3}2> apؔB5ܕBS٬ҧnuww+e d y"HTg) ͽ IR&Q6u@]]ӣC Vl&ވ@ԇbJ"…'r9kȑj0 tC_* E8=KS.SMM٬rs[mm$)NkԨQV]]jkk4[ysa aU>x˖ɲ,r9gfJ&Q2t $iԨQ;vvءj[_* UŠ)WgP,S,Ӥbdwמ"[eYg ш#_{_J!]=qĉ֭:!t€쭵Ueiƍν ܹS'N x<>W:u( QӧXLx\XL[neYusï-& ? 555yAŴ{ng?>e@@~֦kO~z-mܸ1g̘qcN>]ׯW[[쪁m޼ٹ޽{㒤67Ѭ˝0/7M8@U !ޮ?u<֛o|~I'UM6͙2زevQ%|Gs*%i+H8+r9q'M4ر#` b3fv?Z>\2Pf UP~ ;HreӜ9s_{YBeYbN@"pg„ ZlV^彆STWH$_8uY~)%Ÿo޼yyU?y;6ČSǍl6l61B#FPCCۧf{t]wETeUǨA݃vsJ`ܹyU_~P`9rƍ'I:^ao̙ya u ,,ٳx mذS&߿_, :paճUJf @|کwbp`3 !,K'|^u+kϲ,544hݺunO0 +Q{ `4{€=@gv O4r5 lDBdҩ؏wXC7Ugw v^}}yZZ)_=~!dz?Nv=;<0PEZM'xŊ mÆ[:?ïdl"PKK+d\J@ @17m  3b bAo7H$0PSSh"PX@P/l5E$2 ǎD"~辤:RV Ž\Z~6)cAՁt:{ܑFB e C OyPP3&D"}K㯺J D`әgE֯_㯹P+ `\XaM^!kRL& T P J` AB؋ S#.>7p"E(@pg?(L:FT3WX ^Uxk050 M眣%ry  a WE5€_:˩ߙ&`]uuBAP0O1!o A Ԁ2U 4L S=hL! ~GA/$ B7^6U2J!*([ylt$l^}fB!gDi R! /NDxM 08&0 ؁=R%~S z.LTLE J8{2߯i7NT2 C9WtA#g#룜o?s}"d2PZ.uY4 8 a J(g (ŬAŋy 8Pe/&XHp5؟+v0ᡳ9x=u_;0܁t0≮f hf(:z.>^Ղbpi O@ww7o,U *:xXbx)a=}xQ~! o+6U(‚1M)K7׽AXca!(UBVҴW3555M`Wtm@eó:0zh'$ c<W,s@J lWܕPhUN! ͕0giuvvf@ ƍS2 {sfN ~w(pO~ߋ*AAc,?{;rw xw .S4+/~7ט/{O>${еAXªͩt:xac,ЮU%y~A+`/jBB^A`Æ j|E4fg𭫫O&J&Cv 2~ ^A 4_y;kVSS#Fli@7Q Us;kfA }z˫5H&2~/ D][\LȮD}Uؿ;k׎:~]jZ|JVxpmaCrJJ n ,4>_aax啗 ۶m  DER\k-[ġ{]v`y:ނy7| Aii) G=|-ZǥKШQ#j?+/Kݦ BQQyp_nć}ʷ_!?|7ĀaTWW]V8Y\F@x6'Ծ>Cj_2"!ٴκTVV"66Mgِd:UΟ///Cڀ;0 8˲n6 qqn9.@nn..\EzA#3gڔӧO]ɟ A]][yҩ+uAPyԩ3z;Fo8*]t寱(**B6mǏGTT#lZh)X'GĜs߯iӦBE|=,,6EFFI)%?ő 1@OMt\)L CqqQ]] 3ut̛7{ur0cLU;H A{ołp={0~Lp3 ʟ0yӘ|>Bp}Iه#C6P釒<,Vr555ؾ=eehݪBCCQUUO>9X ɲ"›‚e3bg1@]`sr\! GN>l(l?v;݋ ᅦÆ#88XBXXq~~C}$ sбc_}H[nE޽ѱc|8Nv8=/_˲p8/ЯooF-*-D۠y| ƌ@buABυ@ gϢ={֭[c޽8{,ߏ~7oFϞ=Q|*++EXVX,X,l6XV,˟1S.1pM().7A !@EppqڶmI6mq%bee}xͷ㑣X,3g#"w((.)GYzH $}LRRncƌbg˲GBBg@R٨FII M30qx75Tc33ӇA !@EXXbcw^u]ذav튐t>^ٳ͛_3 ˖c-h&=ݺuw;ǝ1_ ǚ5`Z|ӟBϞ0|$&4ǸO -m q~-"CA@FAxÀa{`Y qqصk~<!9pRQy^.]s{'6l8 .x 7܀S)OEb A@ "88Ç9x饗&MoGH $ E}}eYX,aРq9Q1ڭ5k/#$ un Był0ɸ 1@ !  @r4@-- (A@  1@:A$HA  BB1 3@A  $ji 1@ H4`A@BPa=`Uf},o$ &$!@ H`Fߙ~I(Ab A׻<{|!HOA@$&g8 !@AVlĞ+tMVf[:s#  H ^(u+NJP8eLvz֩0 !P?O:,>{, PSsAAHJJBXX= C DT4b@*[H8=Z :XWV`uV EUU%>bbbѿ$ˊoSl`+"aE촢D7řsA#1@ Q%Q 1-'2D=@V| |}tꔊÆf'nc޽{:l8%?,-eg (P"@؊[/YJPyBB'$ft{v`ЧOt|58-n+_*t~[?E?~z2R'>je$rT(fPN(Z煌y1S % , ~ٳgQZZ={apwzB-SHyv܉? 00mc,<;wc())/xUa 4M<BRM.5M_@kdJó-RSef^Q df҇[~=RRx! eSRR3`a0nxZB?؀?`/!cE"H :୫^j倜8p]FW3 ^TRDg@:vDâ!!! )I&=u]p8l6"## !!!.9sIII)))8}"7ѮaU''䌯P=J* 8p]@GCPYqJV@UU5""DGFFm۶_+((@LLb0M6Ǐ#ҥ~%A.sZjGf[FX+YA˵ΤHzB$%%a=sԹ5ƃ!11 'NaYxGGðpKA<7#}{&MoGH&"p#{*@om6yM4>9Pb!7ycFb^ >t}6^g}+Tz!;77bϑabXw~OeaXAǹsPXXDEǠkh֬ۊuA`#5M. -65ykA2D@|4m@W#oX&@n!\ R-jdF03[jooDZQpPІLA4AP!pk:+5)<7RPe3 H  -{Պ O¯Nx#,הqW#WCj#' AQP@z<֍p!PPgRC,.s# a)z;i QVxA t3z˦䌭^!v9adu=HAb0X)K( m8$èmT j6P"D? Iz!A W5(J\r3PiWzԈ 7%@]W&TJS|ϝĒBe  eTy\690H0z% ֐*oPP A@BxK4ކF]ze)7#w~ (鐟!'S#[׉t<&JW<?bRAAbyx x\˨=@(m7EA9$ 1@B@I9lPOk| 59M۬]BC# 1PQkYPl6aԼI g@Wرkp4}{1y 88zyF؞1nu{q-n=[`񨭭DGn#>.Qnef{:v@TdرcϿ#)%b0d())﩮ܹqcHNJ5%눏9yeu +Vf0 V+^h5&nc]غ%}r,[<6 NjQ\RV?|/܊SF~  ?۷Ǣ{^\Gŗ[ể?TWVBɓرs7=,_[{v܉? 00mZ8!%Oo"cPNE8N/BCCv ڝ\| ]cEn(fϞY$ /_ŋ*caX`V03{|IA5|vh`q_4X4ѬZ_KP6=.)9% +EHG`dgg#99M4AUU5 ߜAbHFz oF&#82)4dQ IDATӘoqf  Aܹs(,,@MM cе[4k֌'&z95KRn*WStBFTS%KIrył0ɸpPx1tj}X&'(bFBgVujF?yw$  1 h-j1Fχi=c7PmM0 MAb  Ģq.6=#%!6KaL(vP>Ab Ey"0jzZCK1z( @#/ep̌vԪW{ss 8im9 ~Aod#= ZUGu:ȾԻ =Q  1gɗMB!Q$4{,d&EzEoO Al99G}W YVf&rj=cTUeG妧 0:5D)ao333Qkڑ1u*,C?bm=r剕%t_mNСjsr~񼖾>hߘ'Ȓ/s&':rEck<7Q<ת-6'J Nkb4-T޺ê 9ϓTd!##7yWoʓj}S4NKp=oA MˎzL2N@}NmMOMS P=.0#v=3Abϐ3L'B[7񼮂(#WF'x H JZ=`3=AI?x >G s##=˽&3U!s[pM;<- @= F~2= V<Z`١gATA$ 6=QmvsBoσ,6Qp8X,8x{ر~3g*γ,GFب  Z{]\p~SH˽zelWSSsPVV֭Z!44UUEi ,+")TҥKHLhEŰX,ˤO TL46ad5UӨN~j`j+a#D!y'555`)Ç u3v{ņa,!,_  FBFA뜼j$F %:[p'+3S4; 3jpپ=;v@޽al6,oƽFdnwl9^ƉEh&^ݎh@ ^Ļヘ{ڴ)_EKkĉ":]/K,F^1DEEc)9j4VlyXylx=\tO? '/>.s0<|'p  .}!!!ObPdt)c#`6+*p[v(22+gϞEii aq1zš5kPYYpa2Zصs'>SW^´iضm;KEnK8t|e5ksfcx|=r+S3`Ѣ%x8s4V^ŋ^\Gŗ[!4)V X}X'cnX,L/ ,}~ਬzW%mZڛR7|"!@xh")-%%Q(*\=v= 111`ƍǪ+7+$0 Ywnc޼ jEiY*++wCw>0 -Z"> OaxR 0/<}V4r7jkZRB  |V+ DghXm$&MF|b8m6"##yks iD|\4bc"ᖛPR\Vf\\4믿=wa`Zt/̋N:Ĥ?U!>Ϝ9${SRRp)EOb0ڬh|=Ɍz6=Kb$88ղB8TUUKzz\JxD;%8q%nA{B7ƏGbٲL̜9,**/""EEEzXX۽ǏGdd'1@1e-O݌5S R+tľL9hx$%%X^vGBBbπuw{QXX %˜8a</uug@#3qΝٳ$Zðp<ԩS3{.^}O:QQݫ;ztH̘1<zPAQgDPf 0` x;wDՑG`ǎ8qGePQyc<͆i50y8!,.xG$6l8vڋrعim+/88K>_~ñJ}+W#/5kסI&a1X #v=AQP $W1|#;;7n7|7!;;e>|d0!1`qynɤ>WEeyZGfV9A6@ =k  Ac!*:, *:COB 138u(ͼ&M|=Gz{u jC0'яKAł0t}EN~MVB 1#/~vPjܾWuR A0J\A$3伩O B̑F#FB@ @_xQkݨ+e)'AS :}2AQ[m3} H Q7L m̜z ͎-03I`lOqPSY.H]AlALje|U(z$7b"A0ʞ`35#kֺx;u H 0c(%^ #=D% H ku+ffJg-ϤC aijDA$t6*f&(dddxQFLjѴm>|3KZƛoNA7^G֭eQWÜk(;CdeeqZg1ZWVVzOXuko?ۏq'5"!13B?YhlXm!2b^ u9 b%3"tIV(a'4A=6yH1l1eVBoS HOM%cNdVhY>(N̚",W{ T@ H 7#]:[\ &ƴllf g#=B\܃?%!=A0T5ӑt}+݄gq}I;wEmN=5%j2\\:cϒXDA8ٳyybRZB}0q1g}p-ھP6'8驩4mnd]Z{rr;gII>ֹ}c0m{Fޱc?~;A8Y%p'$x3r4K9l;;c+y$yN본eFjFԝ~]75wE}#|9uSp@n_~^xr.ױdŌۣʊ n9PK.3JY@qtСEd?_$|#[~c#4$f%TQfDtСPPF^`en0߄?RXP : 1`f&2.Fp0^ 5+iA@:}H ؠ1ʌ2r1r:¨̪G=JLw{hZ!G!t";.naq;3`:Fd=װBV7.#Q!̇e9=zR`ƍ\x /I^uVQѣ6mڄ:;C``X0[=ZUI{kk/nwnwgҹ#.] !f$LFnm9k5) zԡ uU q`|~zN7 عk/gf᝷Rtb˲`VUC~@F̟ s/qwnqR(JkX0 ~8v\w]#<H># @0jh(S," Гd I)GaɈFPPo.… Xh!nj-_cFܹ8c`<>1u]S߭"88݊Ӧc݋k▛oBRbKL0555Ąq0wl RvjU8?2Æ l˲DvCCf9fQϮY!#')0[r b׽C~[pǟ8(K.q((,fCAa}߾߿?0 w޳_|{Cr,_n+jqXj~9z6oQZV/^gG!CbM?֒s!!`]0W]jWk<5.AW}Pk <8>خ5='Ow0g\$$DӦ9s&ؼ lcZ`ZD먪BXXUt嵈+,y#..1ј?>#p'U&c1o$&& << /P^rr]vhٲbcc9۶e@мz)#w73hCm{LA 37™I<Xb ,<狋qв9Z4C()2v8.F Aeek mNHHKLL©Sjq(--u+P^Á Ï<_;t0|8&h{0p0^ WA`TVK;?yu>}~{\\\v܅ {(E'9.]_6}Wܹ[9EEEǏGTT`=rms+ӘJCSвE knn#.]➻лW6mS2Grm4i2Zj{ }zDll~x䑡lZ#CGD^'ujܧX)2@: P632#/pu@ra&|8oa|]wᮻ+Wv0~S?k[L8'Ntd"m`sd ੧&\seWW8ȷ 7ny`ۻukٳ'rO3 R)0@fn=l7AFa3;eBDFFFE3[FFx*mIÈ3S*4EyС`cc/3~2FO3EYY |ţ> _' 1"A<h<}훍z62=RQ]d 1H+8 QVq)62b"hB:t>4b?J@FwkuUѵ (Dt 楃%d4zNߌ) F&-ӚjZUB@a>:f 9 ɊRh=.ϒF Iw9wU$Fi$&U+[ۯS@|Bbm-_^{ff"cT>Qvn.qA Çݒ(jcNygqt)tey=ux2۷:PLrJ Kb@vI|zԣGIeW{Kp`}C߾3!1JOM&@cfTf쭇mkTQqFZ6R"LXPy g #")._ eap84-A0 5bfyo;8ɥKmn1ի;b3 qX,X,lZX,1#6&/_nW%T"#!2.^nضu+}-[ġUJ"x_())3兇""_H PȘ7-h=<@R2ѴA50!ddL __gfL*jRaZ,/8r e݄+ ƌtvCXX?Ntpd)JNTЇ@`z9hmޣXII2Bg%Aj \v5Mn!!!0m [u/7Gbb L0kjjxB `̘8sƍZ#9)k׬En#>.Qo$ûn4m 3w'Lײ;;[".6 C<R'_~퍸(t/Ͽ_ 1@2ZsduԮxFM+%0@wƻwa}[,ؽgn}ߡ˖=ϟwu[/lO? ,]?j =z_nنҲ+^EŰl8^Trznz#Ν;йsջ4O~>+ڷoE >>~k= gZʓ'c+uɔ+W59ﰏ7 JUVViSyRR/qT9/\).>wape\ޥ%%Ht)i\B8 ڵ&>^~ mڴy,'Kz=tK.Fnn..\EϥOֿ] 7/AwF&1f}I}SwsBϑ u#7WRP;8;7$x֡Fm;';;ptժ~4٭[w|v7|UtdWK IDATv]QQڴi8~8ˋgoD-Em۶ Mv7})͝]tu !5a"{n vtvډ%KaSܮ;YԩS3{|!̌(,,a!Cb8QTsbYP绕עyy`<ѵkWUUѨ AII11͛!\r}䓏odGH ^M,g䜷1FDR$Zwe21YHINiXy=еKG4k Ӧ,oٳĄ7 gL6`;еK'a\xs@/_ls~_l%ܹQXX;n1|sgUUkt"$'knn神KOb̿F#).5kWuY.2-j@(VWbL:Ѫ#(5ޮPH,%Qв1qtСE*}=GHE{ - iXBG_Vf~Fx3=Rizxt $GCg'ɥ,veP=1BjETi !@6!@b FZ\%b:L x>9a"Q px?OuB}=OFK@=!дo8a]qgPq4k⳺/^aaG]eu 3xA !њH 0bE=JmU,D`% raBaMѬi5 5~PPPѣG!%91ё8p6nܨ~ކڋŋprba,`YS*hi y齙2PLO^2@#%Tۥ$g@88Y =z`箽 w+/{9o,˂aXVۇ)#4J"!PkP >QR7+7< gnZ .]@]]v;bb3nqHp38.\E qSh<3ΝmaɈFPPo.^vc/bHNJikVeYZM@x/4S0Gr_h*@I(IL7moD֯;GΑܔ)0idk>l#9—E:6mނ?AAXth=7| VXM?/WkWZ_Ŧ[oA8fE'Jعk7|]wm!M *ٻ@Ȼ v2J=H#\(`j J!7Z2:9μ -[ĹV\Rv=5mqݨQ# Zl-\97x -0 fΜac,<8>\xwΞx-Ha]m@bb q,vKbjQ\އn>BLL _۷R@=r#y1vVf&Ɋ]BbC"٧99&^fmD'Z0vf3seYrA;~W/]߀{0(..w0WX8犍,,SN!;{Ǎ'~vE((kKKKp>\yeeehٲ%obb-B7#VHZbLO" v]$313`&XWҨQ#"$$PYYfxt7`x]ZÇ}[(2ZNlZgoWRkPTT6mrEGG[?~\I DDfѭL#99ĊVfx:bf\Jv+/'Ƣ @z8L4)8uuup8X0:Κy"11u/5/ Qxɱԩ3jkjAv7u))O>0͝^X&Mj ̛,ˡIh(ѦM[\~ .W ͅ0=z,?oW ZABBk/Vːmn=?ptvwǸOvZ7ݺw?>m۴„;a_G`,t& szZ\y풻vҤhժ. -7y G>6Ntڕ&Bf]n.f+}ң`7~[}RF_7nxzʒC3}G|Ӿ l35Zڃ}nJt[oQCuuB)v~19ry꫇@h >FR8w-.o bF@&=2alTD1@w&ËB: SЛQՔ%Bp9PAfR!A $ g lRADÆ<A&ABF ~p) ADÆ A 3@~6  aC B_O#AY?@Hg aCTT QQQFSgMADVQQA@V[K^CߊF@V[o~XI hJb LeY>Ab  & Cy L >AfRBO BAΝ;GarK,=w)Zw>vkA33@;!н{W ؿ;yxq`[&pC~-~MICp ޽{Sg@v<<8\cMiψ=8(c1>zA׿zuov8FD8抈=e $X +vCH UK=˜[1$xۇJFhcM+cX#@0K5_?GD}>ġC?F֭y1>0Ց纠wt"`/ѽ{O,[ƍ@H/ş/":*.]B]]zX&>oO!X`ZaZ0 , ._̟?r"88iiiE˓~͸{<(..EKp! 4M4A-~z!;Gq^}e=^X7|x睷W (m/_ me $X ba,Z-'K}>p'1`qp/&/_FGnݺ!//իF%Zk׮Ezz:N8#G <<FCȑ#q ر{B࣏>DUU^zt3OG~ 'aҤ)qDWM{ٞN;uV$O ,Zolh={,ˁe9D7Ë/N; *2,͛ѯoF-7ף_"+ 7-!}8TUUUW_T}WaΜٸ]$'%``Yq1툏AtT}B8At/^uΎݻ֩Kb4l6ѣG1m4DGG#** < ~Ѳp}Yfs=ݻwE0}t<#hڴ)ꫯ !p_a{x%%hc>}z CR71=qz*VQ!bСig4 ҥKܔ?|Mĉ8SL¤I˯y8r䈛߻o/l݆Lide.e{RZ=M`(-Rbl6D =˲7#$8{bboVfh % $! (^(슢 O\C TфU }\%ŅEpIB"$d.U*OI&=ݟ3}Ꚛ~s,w מӦU>W;yM}}{5tPM:U_~|̙3`]סjomm-Hjҥ-[ 6ha/~QoF8o$i̘!C4y}* j2'c޶Ӆ߹Hcƌy:9:Ⓡ߿<}|G;4JWڴn:mܸQK4z.t|׭ޢ>°,@~F5}WZ}رc^}{ׯ_Jꫯ|v]U{j7jƍZ:ꨣ>s[8QiJ ^7n 4HӧO׍7ިo9}SNq^zI/䓳g˖-ӱ믿^'ONaÆi޼yy睵N;i޼y{qN[}w~sբ/!;6mO_0!ԭ3phkV\:聕̾uizgU( H|^A;[^6l%\|{S;뒋/ /7h_6|?iժUVn}/藿}^Wg9@U+zۙ?^O< V^N:IG}t)S4|jooW_)SXW .ٳu=`Hgڸq5gq r+_=]t%[uw#aO0!ԭ3~+_֭['SO-Q?qzIZfv?^W]5_レ9pi8bONЊ+4j(}ե^~7sEo?p ۫Yf) C%BW_Ո#}Mk/m޼Yv/^0@-3F%}|-SBc=V֗'5jgB?n]V;ǎyVZ^ %l#_ߣ^}o='|3q+p ׳6dƍ[uWO<'~iӦ]>t)'c>:Jwq~SG~Z3S=B;[{db ʹP*= 6mn}߾N͜9Sk׮AzXZ l݂t)H,T`AƎE묳ڵk /ji{9WG [sϯ$5GQP%rnOk/-bmذ^:F~3o4%iH";8i$M4J4NMos@GGz{ -[Ǐ BC6[<u?n}KQCVo렃 B9azPbam(Lc=_5yd6oՄxvQ'L7ݤѲՏ IDATz!/oE V\ɁFb?\xzժ~ٟYgx@ @!B݊oGQ$PbN(O=%IBW l^uo~@=C iszSgzƏG:s8B@ 43P&'B_p @sC  z=79 @?AFKphvg!!hnp Pp6?\3 @;^M@s3O z !  @znr~!+! 471BsC ^lg!@fwBg @ g#@%@8 B@ 43@478BW8.Bp%oZ0!@@43@- B@ vymq 1f! q`B@ @#4+8bN zB@ r[5 @h$Wq@r \43@\|W,X#dZHS1kx3("=7eJ3fx;!b@ҠPy[e.U(hs>1~# )xK4&.ƞ5Ӧ` S $DHx4).v=d*Zs!` ? ӺNg3 KryiOOz?=y2\lS{NOM)>+y(J]Xe F?x H>ߏƔQ-hצ|91+В˕\}F5{i+WkzJGzUJ܁KQ(׉O? VOuӧNA;bVyGo  ;W9/+.`^'Iy?ϧ?fM-0aɋ[ HA})-?\ܯyx͚W^Ys&`\Uϧb}]&`[FĂ& O(HF^ښiiʢE?w%qh>!- SX,FU֮MGǏ/y}ʕ\~:g?X 1M $B Qր3e6v[`ڵiF "5HEE!`OD yAu ,GHRqa/"b^zi$YX $W0G}/xm Za,NOEAj䣏jhЃ*Rq x.7::4e+aLp\Fp)d-1pڢIL`}$;իkʕ P+c|RAZ}_Q.n/6=q'm < /ޗ2{"aBOnq!T$/ƅ?$K3 9 r( c݃MAP(4G 1+E)e~8_}N\=w礕޳Z.\GȁTXm02z* Q[oΘ!IjkiI?oX,\4}{Bp\̡|FbD$!x[dy |&0>cS>~.I|LHE5qh8!4s5蹳j[IB"0(q QT1[F8ntA@ @cs)03w}eP|mi+@\K@2ձ+ g@ovtB! H,`pB--h*yW&J\0I }_Cڴ7nGE<m?Г{~(ϥd ?VW-y2AZ ֭ӺnJwyM#g k`(+$IOϙ@H 0H'sQ(0@)a|eka#} j)9qjԖ8CV=~Y@1ЅAY q͂Q I+y|v*LPaD5`-v*9vn <>@~csb܁j`/cFU 9’);U[ȄX$ l!$Y ?ˏ$jok…1 D}Y% 8P%gכp}D)NQ&4edB ؚ_%2!y}9M[3 ?r96HhS">rbMExU\Рq 8EH~.;@a!ٞbSKh/_AAIN+P!4X"*dzQWV@fNtL`9f%o1B8'RmYBsJׯDvA`^C esE1u'&_w5S%n/^-$,\$D-ǯ23!0E2rv!)*A-n@-óD8pgU AuŞ5R1u.#9 i}f zL2iQ\@ @͏>ZZ$+w8D.U[U+eWZmD؋!8$0D@ @} Ț8(UdpjDTLe867mTl$7lWA)DUuqP2s z=v-v<`~od Iĉ'r@ChHڵzRx.2'IHr"s#Gqz=](jHCDb!mT9A-J3*@_FFq**Y޾y܇IzYWﮡF( "c;QE1@#C`; >Xbhխ]P,a` ^|Vk{&J­]`?Ke38AO]3Qؽ pY1u,QR$CQaPkVAɨ e0.Wa*"Zw 9kX,"BQ=Րp?Q Th (Cg^WS CJRhޏ3Q,$LCخ 2ln{Ȳ + MAe sW59x-\+A)"u 1' 6>Pi7]ʂVx\fϰ@(pmDف=/;h@#hHEłhY%B@G8oj۱ w-C* 5P粏E0]|y /Vn@R,m 1jS5\A=CsY.@Xr0 UC3`O8r q*v]]*(Â* 6A p\c Q9|(C8F6%k +*ݓVC@U)0 TF&$meTY" A||K%N9>&#y R֕~-C UCS!PM`=aN@0[5@bV!a*J{@*(k!He=u ̉r 2] Bޯ K * \8 ą }&8 m;ݩ +['.jkeMk_Bܺwϩ$L`vKg0 1uͤ 6A1L.r\9gY7ejI5 t PF QPLT#N2hh `:5--jaF8bv W*s% 3dDAB>8[@|3D$B;8gouu$7` ͂ZS pM*Rɂz$2\B!%H'~CN.@ `XfL:*oVܙwҀK`hNW j Xbб%.!W`s>ωMmtvjĐ!iv 0, I}t5İR@*,kC`ρPerLSTi2!NN*ń U(/ w ʦ-kd5_Te?a`̀}N}T3>xp:<. "#!U2uc݆B PApg>.T{G !0KV9LFX 5࣬Duw~c߲de%n0p܁A{|W?V)a2`+4H`?9cTkQ![D@4A:;58yg?qu ,W.rf HK&5Jk%3 NA>\}fwtpbCX?_owuP( Wn A0 |a`a ̢o 2`j $ Pg>7b!OIMmC[ZaB+~}a(F\(^|(Y(Q$?0yC +lP-(F[PPg>wth\X@ wPPwP6^`Vh m: a/0#X0aqxKx1' b+0tKš bǎ+sg^P)o]aVzW ݭ7::4e"N ̈.Ӧ /, "EE°xR$[a=$n"d¬%HDP>p!'b*B '=re@aXB $y׊$bG+ֈJb o͎qB BϙSzE\mr[I,"ߗ,f ;\(Y-K 80:9{.\~Zed*pjb"! ̩dW,{U+ʬY%CLw ڒUppmD΀Pro`y3,BA+6l(~(˕Wjg=CW-w 4 tKK b .GpL,` LH&X2ytv2n|=w EZZ܁0x¢mDDo>o=,8V4 P H֝w K] 9WA*T\u]jYA¬ ֨ Pw2PwVmܨ ~gCj!CW(4fM`8Ja$PH܀jЄ gHIDAT VkgPЈ!C4L؂Up<  W C Hx&,X'N=UtwkĐ!֦\NB.W*YOEAK[F80o tGsI[O@ @Ws>1@ b 1@ b 1@ b ``aLIENDB`mm3d-master/doc/html/olh_images/screencaps/example_bool_subtract.png000066400000000000000000000675621324021725400262600ustar00rootroot00000000000000PNG  IHDRWbKGD pHYs  tIME ? IDATxwxTߙ ^  J*EA&H M`ЋxAEH BD0!@$L|3Ô35=y s{=e{_QicbпHR6-~1@QQn݆OO0x?}BApϊ fkӍB\?ۮN886غub۵3z>&6[}ϽH$჈i4He &Ñ#?"3# 5`@=GRfS1Ys5{ BB K!M臐 {F]]]臚(J~roa.!F 8sbXa#{ԩTW||ԪUNG&L&Ӽ^x@ݾB7O 2O8 k׮\sҥ{"7*]WŋXt èEaGPJFE@P%XxK0j(,_5uz}5ڼWѱذ tڍ@[s!v]F^:;IQPP_8kM&ÌNxq"`ݺd=rIkE ^_`ٲ L&ý %ѣ'X6Eׯc[@T",4srub`ɒEy$]T_@NLscIR~x睷=~??B1M`WnӼV__mBWeK=8H$\xcF?_v [?ކ; 4>={^s/gѦM[qZl{o4b 7PgObE;:bί46]pcF?_~= D u~mDY!kvZ]j( h^S(_&CTTqGGGڵB t?$ AJB}}a:k8=+-MDzz:*++4"D}A'zQQM111~ε󞞞$E2NCW26!XQ 1nݺ7 SsRDNNڷo|2cϞhӦ:gx,\>>>(G\vF].bS@@:M"82'(!Nej.6ݿ)=ep&b̘2Di{ɓ?aŊexuzًހT*Gќ82wx QQQ wkkoe鉼\X *Js7233uV .gXkC"`9jk8?=}bz?~ܪzre"{IX|dff 2* +WB}tz{Ayy9g՜2H%R$d΀=ZTUUa]l,QVZ;O 88<0&{Z)6AágȗzB@ƴ@UU>u낄c T*}1ca1ds?ip9B[L҅N ksF S*kׯ-\&ڵ3:AT*!tuĠJRsiۻ !|PWW%`L4JJQ PSPsh!ИAII ЧOH$p}E+P(&#^7$̞2^~y&22{78w6~%~XJ~\ƀVk?{MDоƕ .]DlLF 111l VxJt P(Jo9?Clx"# H0Յ4>z} ?3:7u+h0BLQUUOOO0) UUU&#rllXol\VZc>aH$`5bERoaz@]0cH ቊ GyyBc9P]]BQs_.]G[X: ͅJ#Oȹ+WW"q0!@Q7ujL sqQ+?22T*M RLDDD s.xͨ@^^fϞq0}Tq5e]&J1q3xedgg2220}T~(#7%(hmYFܘS77r"-- *ʨ8vM.@d,7kС} =8z뜿̿' * .]7iLy}EшIa!|\ 4 A?LlIqMg}# b- BRO>:=z׳琐0NgB}-0ԣGOk??Ic0vl{[j//7bs:ƍ 9q\DXk!HHSyfDGG BhX8ƙ PD@ 0&( +SR0Ӏ0 sMiAJT www >BUUѳWojB1bO74' ct, CGL]os٤֍iCh;yT \΍ŀ:|S+ə+XbSSNII"oN26DF(ĂPD@)՜!!f)#\èv`S^ b C@[Tj1'ktKYl{BB1DBA2SbcvDD@!Sy5oɆD(B2!bbbA`ZUEe}-7t=^Al/IL@#t朁KIrRLxWۙ"!P  1!Ezƃ@FL$'%"Fl'!P 0J`5ք 8S+ & `mpP !1hs1D1mGGKa 8 "~b {dF֖MFPP Β)ub`>{:01C) %8pxq  B1@MDY bEĖ-+2ڒ(H'iNp/X( o\{8]]<8RX+6!bqОS!kk os65ck#!P 1bjL^(i3`M uc&g"ДvDwII PUU wwDEEA.M'-$ $DM Qj%NW [-bBI}NI:2 @UUOAAA>eعCn,?7r !麈 ^+eŊ2~(ā5 ͜5˦bzpD-P{{9p b)UUU|g֭ ƎqJiii٧36L9Eh ]{k,,IšKm5w˘׮!LOA׮ѯ_[L&Cѵkg:t -GTֵ3qpi(̘1QmӧMEYYk:0QےhgC4gLT0% X2B!@MII ЧOH$p}E+P(&#dH=v _dd#0g,׮[yy8z, ii?!/?k*84#7K+l1ӐJ!Z0f)[ bl$"Q[gҼt)11!` 777?gud@TU Dɓbv H|J(*P GL>TOY֮}`ɒ)ň syb UUUbPUUe|-Rt^T*h===QWWg0PTT(͵111~@O55^LdX28|1D--PY,L!@O(P^^@:h^Bppy\opeh/&A(m!!VXk7lq`KB̔Kvrbo`(4$QQQ8q"J}}=233ѭ{O׌Mx-!22 W`x :njH^ QDE]P z޳~q[f5;mY II_GyVF)r9BBBJe0P;v a& 9s6:~;( #cG̙UY 0ƣw|O`y 02@[wC`mmqV%6,qil-Cm(!@ 4۷ J>}둚_ϞCB8 ʼnX85^[@7֭ۀu6XUqNIW1ۧ.9) 3gykb^O]V~͔#47}ԘK4Mam:-Nre?v{XS%+1U~gs=<<0`͈+аp$$3ib@Kq6v3uSYhc5f?6Vk գݛ60׆oSLDl{_=5S{@9Ww@m]ډm9T*R)1|";; UUU F^3#`4nLgZIx֬-`I_lZ&OidD8l@m'/J!˹1aFr,z(v~5NڒU% ?9)ɠ@23?B1zϒ}Y>vbȇ%.lg&&*lqf0$5곧 ۲21;YB 4`F@]rRZǩ/,mCP0B1@,aYQ^Һb#q8vKdSbJؒB!XӦ9[{,kgsS91(!b4HP{ 5$v=!siklA!S@Nb!$afa~c &{ގSuџ`H,O3J@ 5h/+v>sTI"fC-b6&#wBhB]tzn@2H#G->8bGB3Hذ1Gc 0vS9b{ll-}n[r.!b "fGNfE=G=,w[!bG 1:3K7#@g+ߒ: !b͜7ܭ+uC{8B8z!1,BI@hFBZ初 Y`A9:|o egEk,c). P 4C{ܖLsԪvY 3-q֊ [7tX :8zN> B4[ިR9ѓ!8jX{ 9Dk{ijh| s  @"{.JKкUKcؽ{̖ #&:!:tvZ-2555 ӈG`?7?(+,YV!`*@l4XGll_{9n[mfh o m1}49{/FӦ!2-)*++MiFj ddfcdǢ0[j#: CB1 !# m` GBֈCeR[ؿ?]vF~?`@o>]vơCnV4̘ၻoN[ (O'27p睷#2 Oj@PJ%Bt{76K; \xO DF#4${W^S^^ CDGE`& 3fLGTd[eee:ֵ3qpi☨%۲^-C,c.A\X⢩,C ??}}裏"-- %%%8q}Q|7ӧr^1Cе[7],7 t!ԣ] ?B^ WL9+)L|/y= &>oz<~;w˗jp}N:uhnZ4|$'ѱ'1|kG9b!yWX+_*Y=ry-rdn"F9.]DlL $ V\:M_cʕH$f-wރBѾ]4&=NXL&Cbr#$$K;wrP*Xx BBB4{}\sC{}1-]hcٲfPX aaa +_\ڪՈ7&Osg6&h`lfSuZْ/Mp(ns嚻CTUUpy;AD([* FLzY޳WdMT*IjƵk&d geK @}}kUT*5["cbbp5k4===QWWG1@9oc""B`F`A`-k:tO?t h߾=A@yyM:sLT02UtksMuu5 E-N7''۷\|A& ^x,\>>>(G\GNN:t`,r-6hIs I1ЀBe3;mȶXԷbk ()pD*J%Ν1c"^yT*dff[F˚8a<{~z艪*޻N;wooSQ^^ _JqހT*Gooodff"..`]Mm ly<==˗3nܓX`&֬YWcXkC"`9jI{2h N߳VZ`8\]ӑdw?^d?Kz\X\.GHH(0tPl߾={'w> =RSS\na!zvǙ3w4__`؃CЫW-޽gs5BaLC=5Ij+ IDATkr2DGB^txeo݇=!,4LtfA@` Gܹmd@)=]PzZ첆6Vl7߁5 D3̧mD6b{lhYacm`Ml*aL~ƾqbz?=!}eWVVbOqлwoHRDA_ϞCB8xxxPA5|v8Lث7h@-YOD0]޻ωYHʑmDHHS[o!::^^^(/@vvB)ŀk1' lvr7)m ce| QTJpww#PZZ,TUU!0(={&1{9KL(v^+y_rПI)T*\.7@M<=UGg˺8lG/:d~}88{ 4dVS[{id{BC=l=ג†vp##B1;7ZAϞr]ˀ !MWX6~&{;1ceG8KGHN .'`1}gv}.G.  -XY[8a:vm-]SwII N>GP(l$by/ b7~0T?k{QH$@UUOAAA>eعCn,?7ef묩AD0\ɅL&LZ.Ř}bb4ZA!fG@Ge;Jؕg b?Cn]0vsV*HKK>Ř 0D:VZiw5!`ʾkP 4 n#6IgNޔ}D .dI[&kׯR-PT8tzaM4AR%Xjy3rsc۱aڵT*d+++۶mEEE>8 k׮\Sҥ{"7*]W`orrdd`8cѢE 啗_>E]/28è}aA`E/!@|k6Pc!}K;#\l7Tv^>+?i^ ??cnjD"%@M߾}qF( d2;v} ̙ߏܼBij}mK:}|}}hzm%VFS3n_ geV`QTt66.\}oo]{s1Yn-pXR)OkS FP;ZkG&*Я@Y[3`z[e Ƹt)11&!&&mT hGJ%^[H$߾QQѐH$XlIo۱cW D"+1f1 )Ӝ=͎,2Ħz }z&1?D UUUbPUUe1E4Nuuu\Maa_#LT*u ز?ذ~-ظZƲ+0|͡ s]v QQ D1_/**Bֽ111~oJpjY,ߙN\Q 6[h7tb OTTT@GyyBȀGs%W#7E&ҥ >h+~={W'a޼PTGNNh_:^|b85*`OG萳vOY"ƱZv9bWLi?22T*M RLDDD :O ^; L6dӧM/jN0W޸qOby,X0ߤ}3K׮]1r(QO1@\* oᬍlg1W,,O\.GHH(ҠRcǎ!,<r.Sb؃Cw)/OH;<9 g͚@=s12@\3*U흋hggJb{뎈 /ő#GPWZ;"?_0:΂<Ŋ[ziy2 3gƥ?uj 3^z~>8xxL9vlMCn^!~܂v^'cS9?`izCDU= $4Q5Xc/i 0PN%"R١hdk9b^{;PGץ.ԆCD0ob~ 4h#EJc:aC6;"a B1L#zv:*\!rm}L9D@h+K;W:K%sM{D!b{,e*B@a@i,0I82Q)70s!M$*AGђSRz`gi̵QGAz l "XĴNIse})):c>vYStArROl|{eM{G#E,cv;=SlKM=?ԩfӦ )2uOǚ>s~sY~=)]8퓓0s,ץ~fY{3hg.P7m232Q[#ēd6b 92|lϩxbDүϑПtA/bQ$b Kw]]-%8#E a!sE1RGajhfږĴP@uuju# v.=Usu91:m])TB.]BTd0xصk{/GUU5jkL^ߢ GqFJn9Yث>W[[>}ѣ{WTWh^kb\=wd|Cb1p)cGF{lXԽnnn777.= fϚe## Z^?$ƙjn*^t+hѢ%NR32gx9fkr{bfASR@pSNb3www x7u|EE.]q&<L|  <,Ja7Z7`xwc9:b`ӛo;;!*-O*ȈpQ6 2,\0qb ٧x;6* 9"{ckO%-)_M#wy֭],Jomބ_ӱ˯V ΁L&CVvr4<H$: 'NhJ8z {QxkV9T*E$oX .`S((,ޚ+<3|L ${eZrʚgtgՂ`ń E>)?BQzaqO> .BDD[xc޼y -ZM 77:!@7_CiioJŋ 44AAX$_~zf16 o $"22~~r,Y(^HIqжm;@R3ؿg)~tg!MҸP$ IJƉNaCaI󹹹x!h6ֵ nč Ek GDDhʋµk c&AS:"!zl)}1͵cF;uIC<i Yg@" !!!3gNb_hh(~Os:ŴМ1jÈhf<2У'V, K,;`W ={~}{3^iGoΦ_X7@ pTFCN-lHI!&6[}ϽS@y>USRz`n+W1!i 0dcDĠH$0`   v B!B(!B1@!  !I:yнGN$.#D"'fCF!9ҭ{w!!8W*Y9n؞QB!$;; &GLt$BC1t SmAPjjjT* ^#ɰr L)O1@!.'qI7:e2v٘?>SA&iUWWxhe_M~BqlI :AtT6nX RDXh : \sE<'А@~\zl}blݻ !|PWWg.C`ƌ鈊l6>m*ʌ3e &NѮ]u]X.YnW9ytwxzx`k+JE_a:\p'OFAarN.d2."7РWs nf̿ީV,_j>14c:^~y&22{78wN1f5Ґ󑜼`>Si;Biؚ@[>BѾ]4&=NzcDDFFW.ĞohΫT*~S,[QQDze+-[`:ԭ^CA{7r?̝;2[[[v P#""IIku:#X aaa +_}LgV1mPH~E !:&>ޅOOpX]JR* F/ؽg/ (R @REťn&(V60@9hݺ-6!7ШC3t͉DZrrD'iix͍8y'j˖߲1ȹVZnn>SiBޟ{>Hhc RRaaaxeޫNs.44 ލ6mښ-ܵaA?,*` |||PQQDg^3g`ذ "8$999h߾=4z,y\*jE]O!Ö=$(**Mo;i?╹s iS eѣ`y,X0_s^^^-o'r9:3g??.^Ԕ3:cÐF(,,ĵkװp|5ʤ1V9[i;BiBؚ@?šկ#C,z3gNc[hO>}EшIa!2wYѾ]{ tz膰0͹Sb؃C,ʈ_~#VX D;wg1U9[i;g ٔ.8+Df i6}վq3@#BqܨB0& #D1adB1˜P BH3G!!.dB!F!I0* Ba!adB1L $a! b5 5232D41ׯBq$C`L>$ٴ-R BN t 3#=?u*6"͸''۶Q B`K :"Q$BqH  P BH#a ~j(!ĕ IJϋ!!8[V P5رrrբ^s4MzΆPzm e22@!.=V T (pa A8e}QZVyMJ&㥗gB*B*_SlxNoO;o_} Br~ ۴S遜+8rj69JJ+2!G>m5h!4)67 U7+?(Z7jf뚞uk1sl?#Iō7 -Z`mrT*,X{֬~{N9k6Ɵ^W IDATJU6maI8v(Ν;z{笭EZZ*+jkkCUV8_sZjph={iZ)#b؞@h[d ((?#:u/@Y_ 5r+tH$\L{/O'зo?Lq6nXKh׋J E&L?d2|p`1JpAbСPOEx':VZÒ>(-+ǵx'NW A=y *v?*ѻO_H%uXgC?5+ַ$݉R[͕w9 :>P ߿,&BHBJrD<==pϽbCPW{GcRt!1~~~(-@}}==ͦVs+JV~b(!ĕ=P=͊#Ҝ޹s! Ɗ+ ҈-M# !Ű5Pk6SC1@!.- ;Q K?7$%%SE!V2.zC!;+ ws;6h=x0:%"i6}>[ DÇDĠf0!8k%  ݡ 'a  F+&Bi02@!N q BQ'!4C@H(!BⲟM6!ҼadB!8&F!BB1@!&l ! #$@H\F!ĉ002@!&Bi0gM@!4o 'B02@!N Bi0P BH3 e?lB!y!8 &WBq"L $ BH3 bB9L $.dB!F!I0* Ba!adB1L $XQ&!6]6itpBiȊ b#ޅvL^Bb`׻ b#afS'rJ0gBJ$R B! L $B9\gB!8@H\ B`! 9#2329Azi~ =2 MNdc8'nwǐ:uSMoAFc!.-#B}Q ~1@\\nfefd'N{=$>x@H\X L2`~)qݼm$HAMg*4{pBbYyIXEJp cb@6ۓ 1}A崺=RbY Y`ۓPw܁3gNƏڵo@FeCdb4%$_=q묬Kx'QVV55}}>X& [@H\Guu5}Q]]:> nl8I5|ApY噻~Ϟ=:t('xW^RưapM*B`xO>^_϶O޻ B Eŀ ~\5M 77ܼ S 8 TZҜ{K.!;;ĉe7|/rssqYc„ `VV0a\rG'عs wo̝3 ;w/__+9vuأ~ݑt I\O $&.A\v OXJJ%O76nDw!0*ow݉{7njOJZ;v@PL4 ee+`2,xu>:EtT6_J@Xh0J%B诹>m8N<^=uÍճ;~>:m=[p2L={6W^yѲ]k.|gX8X8*ߊ[*jP `l?A}}=T*mc&:m=l¢[l'P(Op+IIIزe -[`F3wvBӧ1glڴ Rᮂ\pǏGFF1mڴ&F|}|ʼnp@߾xq"VX5NзGp=Nĩ'''=8h&ݻuA^=oT/;マcxhPoݫqlR##p5ͽ0Uߵkt6œH$xGq~ȑ4?tDd@\iL l!n ]tG}[jO<ƍիW'|&_Sرcei"Xz5իWk^7w%::=z²X,onڌ{ݏ;A߯ΟMϾ:tt=j@H\w?Axx=%paj:w C;w6 777T*\Fv/@˯h߾@}>0` blTޝWUysn0DP)V R-##"-iJϴ}38 L0-AdEY`BLX$9sOnryx}\I큸! q577 /z%Iv#/YDsŋ5~xS#G-*֣>a+/k$qǝׯ\SNɓ'o}Sj.袤3|{?@ <êUh]3w֭[Ԭɓjnv8GNѣuqM\¸ >|X=vs56f6ݰauf̘oQ//_ܠO^y?~$v DW:"%I?s.dT߲FivFҢ>3UVVj*=znr1r4 tTt]P0pyZq={n.5:~h DΆμP]%It#׍r" ;5z:p` (@Q΃ _DgT aÆ%r4 46(t)c߿ qNMi{?4"g[oQ?h&L DsfͽC!r4 pZ !C{kTQQ= A(b409AAC@U @ o]Fk׬ X a XNuɥjȐz&L䐇^{}@@~96az\ `@U@@^0j@UH;0PA! $v a ާK ;0P Y`iYD38^"|p!9B $7OҲ`@80S Ph a @nРee1~p@0Yw40P` ^~8xB!Ez:K TP8h aDt h еh aC/s:3x3Dϑ QHUP(h a@kgR ,)dh aHA#gA(@D@l)X"@7;'[ H2XRr Au '*oOg\Rf8*BC!HiN6KH!Qu *BiU A=@2@K m@:-\:K!^XH8`TR|;̂L+|T 0,T̳*a ۷a! lI!=D#3  3BGӑ% ={j7۪^zI77MMa@6Aѳt晊j-뺊*OϚŋa]U :/`\Я^Fjv]_L*+׿RT\1HgIa-Ke-ңz50fUs4}4*I^R"Dz cgΔׇw%Ia ]=1bl˒mYZ:a9,˒%^ +_nן헮Za "/k/9TRjĖPݷqL$ɲZÀ~WU^pWmI+i"}/-$гɱ,EZ'&ؖ%w1n]L p%nƍә~{ ݮFq_{ SĶ}$v5%^W~=y:Kaض\/ uJrl[hTզ/5qz ap@0@\Z%ǑVc۲m['BJ}֮ fY<࣏L008-a ~ vKᆱ;wJRY޲@X Yn(br,Ktj5z}Dztp̘$EB}7K^%`xh7%uU^nc LAaEciYN4u־j m4 z~۶5࣏Z`_=jf?8[S%nCL~1缍Me@RB 8Xg ֵTeu[JeD`I@?p Cl$ c{m^smTQ۶u] ߺ5f`[(8)MoaqTbjw,K]SbIѣ5h؍3?jv!Cb^;z9mxIDATzI&$4E>|\|z!΃ SgG} @*ɞ8Q~0L7ʱ,9R;Gh3o%nTW53~˒, ~4dm>܄@ A (/~9sq8nǶMTTUB#m3a`]k.ֺA4v ~yAb%v,rvB@3< QpU0x!?su:|:gz 8 ̞~;>f?8[o~;[k?u><]gO?F q55f w-zO Ҳ2i9'Ƕ͟s֯׾ /ԗ6nY.y|P"^0%I Е{/~lf:K T&8`v%LgpϤjrV|qxcYGj$}y߾ }~АZ>pLe0o{vprsilgV3:F@(@OU;x8l۷.}眣Iy*29L3%Icx/$̟7O駒?$M3K Z \Ihl`N4@%lK"  v:Ԙ-Wx]ox AL׫{zһwNoh0~`_$z^4 b6|:i"@@F ^08 M@ xūޯ;tHMl_jSXRVfn_ZVeM(T|~axLg=.] :TU !L`'$?`[n3{9P xL776JeYQ={Ƅ U51}۷ %x @p*AC~ Xq€}uLKz2GM(x1 i(peI˗k…)38% wUU*qs!pZIlҔ6e~OeFث<߳cc\Ϟ&$*\WK8޽5DX0x3Ax;UvAvI񖥥e[ݿǎGs@UdYQr]-)+O?K}$l [J +Ѫ?x{P(Y2U` ={ ?=~\gO?]3@Յ3MpCJyz0P# 7 Aj$! ^ѣ,KI ImǏ=4\M0y0|W  S ^0Hءj@vuW@7}0S -I3o󻧻wy̿Ny| /zRͷ7`wF@j֭8Nj@̟@e Y ж|m޵cJhhSItL{Hr.9qBgtHDE"iMT8v&A+Tޖ + eHwl-dq> @@#GT$"Ce)bۦ,G@d?t7@pM4g^i0݁| x^CVjטTBW 8کX*vdxTd}&{{τ@-1 :1UPow9@̓JRhS T U32a4qb*f  I)Sԩ,G@ՅDt80 A>xanVÊs&@TL?偸ҳ h0MlO2R.ZH@) >Z@3 o y값DR)ܗ=&D`0 @  ^s`xWO!^PU T*H6RYHN(ree?qBeGnmf^l lA =\57{T8Ձݻ$RwKmu!AWȦDxoW'LLt.hr:;s8uL 4vݶ AoThU ALOe9@ SBO?>}ڞ& U /9ГA `&DХi89rD4䬳bGkno -U.XH0hjБ&ĎpI0~萆˲,F"mU`5 sٮ [5HqY~[a9 8K=W%m<7OU %g `{J<8qyʀys:@@^!ICZ Lp +եdgp&:m&WTB88WnKY Dy ҽ`yU$#Epy R̄m0ڼYtE% n3@@U |$1c4 AuebaE ^Vtر_ N-EeaE *w_4}@e^_޺%10 񾯝3GO@9H50000000000000000000000000000 b7IENDB`mm3d-master/doc/html/olh_images/screencaps/example_bool_union.png000066400000000000000000001072651324021725400255540ustar00rootroot00000000000000PNG  IHDRWbKGD pHYs  tIME #du7z IDATxwxTߙ -RB*K*%(QA:"$4% ?EQE1x(`B"$H' d83f2s33kaÆM Ah4RgolA~}0p@ x"~{+&M[oOr0?+ >ÿ'Mn!wD\߹3:]RghooE|ΜM7y{[5;c(+"bط{RGh$;2޿N!Ϛ H Aᶐ%hac/1xa@R_|N466M!lK 0 MɱcGD\lظ Ǐ?ƬGRM۷btL&L&ܝIA 9on#}6l8xxxau&xmۈ酋ګGsktbַQSSwuѱeVW_AQYP'Ob%CCC ^@dd$B`6mB*Bl?cFVŌ ŵvÆЫWo*3@2tK=vm;VR;w2?i3·v֥oɄ9BݱxRؿoסcǎxfBxzzbskm׏,_0L!Xd)nX./\@Ƌ/l6#"< b`ɒgH_Fg?ݻcsG K.^~Edf~C@A$ Ǚ%h׮&\)EťQCڵ+ N痣|2ڶmk݈cRi_WZ|[N8qc/ `@MM &l9*u萜 QR+buo鬽 Dyy9l 1116KmC`00 , ppXl)rrrpRMXg5Bv_xѡMqqqpùAAA 88GN] _XC^7{0q}6י>sf3 ѥKӧ=0} :]Z+S&O¢gkojj53ί_զ`:D8$ЕDEoq2D9sN:$>V\W^ya̢a0XpqݶN}O{+V>bxeΑ~Cem(..aXl"//!K}9cǍDzn -\cưKc)x-$p?<(]HoĚ5iX":&VFI~nFuu5F O<1̙h0b())FBBW̞((}m:X3?L1۷h;cjjmA夦>ŋa~Xu]7o$!A^Xp5mڴwbĈ;M&¬YW `cccc^o gԨ5jk=4VܹO`'8~FuRA`C,1w.Va6a4NtApE9[lZ  H Rlق)S8x<)SHAPzAb +ۿKKn4H$ ! | AA$ Dh}c&AH->}:ӧO'!@ hn@jyU1UAb  }Dk"B#&A.$Ab B$jw2AD6eu萜L 1@ZHILt !A.FnlM/$IT8 62hTJb.3ݑҾ4MMY ݢ= `0@~~>jk/ 111/.3<Ӓgst3(ޓ?g*jkkgO&Ν+Ax ۷Bhhn=e^ZYyY̖, \\ OXߜrmWDL?&?f{7~ ɄӅE-JG"D2 Ly$|+{dg8pUd2aРAٳ pc6a2Ǡfvخ۵s  :hll\t ˖.AׄxDFbɨ(?$ Hpl@4'APQQb$%%`0a0`ΞAyy9gu6`1T`gرcKkwx{ya&HgG=h|$Z!q(ps\Fml!#,,ٰX,bM@ܚHw C߾޿ &-[M6g|II0aXDGEb􇑜<@1.88x ph' H @9r\BSz<bRU@D`p/<(8U@SB3er&:Z.-wV"@ʽʝ !@ \"V-D_J \a!/!l5Ab1BIYR'K eO1#q9FNtq%H$fQJA(3p\%#p%3h% A&h/Kx |a|'}rAyɣC5=jwm2lg>TrGi#AB2.|{5\o߳3 'y:ؤIXBZ `0@~~>jk/ 111Np',,d=.-fI輴PB #-W!Ȼ>K]flϔ;`س'Εs|<|}}QUY!44 ߞ OOO޲}QT\ DD|>h$āEsSS.z`{_rE$=G^0~17ƶømL&!p( Pe-\X)1hluY)gdnr4=@ɞ=ٳC APP ݻwcٳ pc6E_y%!8r'/ ̙31 :fJAUU.yiyt)%Q}F\齰L:M#9TTTIIIؽ{7dgg=܃?III(:{弞!L&';>k(̛ׯCIq1Fv(.)AzZYe@.2\#P#]o_e8Br Clmk+[[w_ (yDԩ<`0`ժUhllASSVZ;qqq f((FVŋc;7...]Ab{ ^'$ضf3RBƗ1\"DhKf)mM 6 Q^v !!?UK.`5 ,+((HHH0QXX.]N> x"zDTHrjl8NHLؼ b6s"W>JbbbpPf3͛q]%z)X,W>eO,~f!Vz18s.=:g5.v7˖.F 0 XpF#,B{( ײ8ϙ݇@LB#v=F:8YrGXX81|pl۶ }􁷷7zwy'ɛh'pmnc)2 ^'|Jg 5Ic~߯0o| gb,dAVbئR :o|*mރbСC1l0[fBa~z&L萭ooo,^/<-}n}}}~F_QVYb.BNdhs~/=- sSS^g{M.`Kx$g{p.z_VW׽[7uJ]hOrl{a/>r|W;=۴ &LĞ=x TWנ 0a"o!klzujlz]׸<'U7[P]sqcI aFNUuH;4͎#k{Onbh4#GBee% Q[[P;vtX@61@]qR]nn9)b(O2v boF#ic"B燺P2-5M/_WJ~FZ B%ii+A$Z^kllV h!|ئ@C~ZHBAPϣPQP}j k]\-CSK@3DҍG-CɺN1I\o\^rAb=”W3PbvrD zq H G@.2jUz_Z 1K\A D*5/ŎCQl@jy;o'tαv_36Ib6D"Q@7M0j!CxǶN{ Rp:X`K-lyXbι( !`ا >>a7ZWlOL%ykc>v\}L -P Èrq 2J c\'7 -vx$pS!gXfH*=5: b5))_}+  1 ;O2@wH Ъ2:J= @+p Y kR8;-bϗCI  QF`h)dScζ7@?Sb,YBIB mb ; Ygv+JvV#WpyO,% 1…%{Zet4Qyp)F[PrWY`h}0 wEE9ȑ#(//׭-lv8Ѥîմ{ Q:Ro]$zOLP[[;wGeEthUeؾ}v܁Z 1e$F#<,ÇΝndb=!6\uĀ{ 1ِ1|1bRGb 1W_ R+ ئ B! P[[k0{,=r Fٳf!:l{=\tGgBlL,!7 ,Ļ[>#߾}{\u/ ƕSbIR <[] Irس'={2&  BϞ=w7WM+s`6y M7݌wy $8/r8k ___̘cGM&B@@; _y%jEoC1u Kr7No att ֯łRl~aO{;?e3|f؂cccq|)& k_|Rҥ@SS #ڮ(X/:1...w87((7I g"d6R"\!P"2TB/V]iBNQ^v^P@uu ydhDDD4᜺:ˮ2ҥ *>e$,z]nG`` XW1ȮOZRHnd9\mXz7#f-κL emaOLL ʲr.^p3u$<֥o֮]+VcXt1m` 0zd(fEP=5v.WAzZ"yE9?;9}ʗAm :GXX8aX8c8Hs5vs}z矏 ŗm?f-v%aзo<݌>7DǎlBacC?H|m:ZqQQM IDATcЧo_<8tCoE{!">>AAA>#"I$\ \hDX0P3Ws"PZa)ωVBX,FxzzbQDAA>jkk>}cǎ{ 1"/t rxlD07Wky*frLFh4ߟ7. >?FJg$?]:PyZj]Au2 = }R )P 6$ 1XC|ZuR>#Nzzw5HbEnKI9-  H P᠆W@+!z[͕bLA$Z@+#(wԪV{l}V{+i H \8=/VhC jNAh\HK!<5 fm"ۢ' B LwG[NOK^s[MMT~[DsN_۪۴4>T|/bc'w{a$D֍9h9f䠃9ΛHsQi]c D a4V_${A2'#'s2MMe]!Py|m^d4Ψ1=8שV} =!i=SA$ =ѻ"N@N;2Rl-~NBυ  1F .S+N+U=5f@rsH/)A$W@͍,W0 ZٓsJ9>,oO'oY(+QDtaL&L&2)\{$*=- su)?=];JJmm->>zJĄlFvv6ƍ///n Ҩov / FlFARGZFᳵA=DVqiiɟ< WZ8!ܛ={2ѳg 8F*?h X, .7%XnذqzꍐfD8K.!=m-n}555~[;\l^} صs\y ţs6mW]]{f<E_YYŋ'  ƌ+ D/5/'o=zDU>Wf7lu{?Ԋz/z?|ž c0 WX0`6mڄrzL&';>^~E̛jKbs[y啗/9ر#Y]ϭsrw&O>Wb;plܸ8qv5|}nݕe\gu().0=ҥ:*m7rryUs]jgc-'f|%}W*8u*qqB<<<?,ٌgWAhh( fH7lEtt <Cj3f/AXX;a@ɹs(//CTT4ټBm}|m;bbba0|J߇lÇ?ADD VXqcﱉ1|6zz%iKICFH#peeZQg ((fxyC ; pز-d؏aɷwDMwyD-,\ŋ6...u$ײ|= _M*Ȉև7jjj0 t 9Ϟ@dgql Kq"uxͷX& σbU^`` EukO>`QObcjEƎmJ@R\]!s0ͼBl6#//QQѢ=|"//SSDAA 77g9{V 8y&̍6πPy'ޏ La!*++p?vx,[8<-\cƈWrZ5E,1#Hii)+!& Gvv6, 8p""#﯊g`cB?9$% cFr02ov<)e˖`ӦͶB<8tCoE{!"<}>` APP͛O=Ze TӠhfTL]bFV AС˯Go>45|ף9pHSV^uغ,d2a'p*O۷ǜǏ?E{-s ؿ?Eť~$fkPy^^^Xj5~??r13ߟ/֯߈ܼ QOb̘X-[< J!nB^^^0a"JΕ"##;w޽{sg@ɹRL07^h8ۏ<|m{o%uRTG4s힞9rO!a0bbQ$2zx2OL]\@ʵjރ䊴DŽe4G^1h`We%$:x 0jQ-w,T55Em& 1ЌF`^VC_n$, 1F"9x,_Zԥ\CBxe1jbF>+yasNu萜 uh %hĨX@YYv~&O ~T #''bʒCf[[B]B}lTgW}\auyh1p  ~1PcθK131iitW^Ė%Nu)}|Xhl;|ZõҶa'+7a#&hk|1_Sz/MMJ?ѥ=k9ROOKT͟>ZuYpk ܾ\< cA6W0YGuu5@W^ @eeołŋ <<!!Xd)>x;kf1mb >>/Y(cɒk0_kBW\sM'CWa4QakAi$Km (`HH փ5;x°6-~{ ̜1~QQcDpꙈ+ꦦ&;q}x{{ᵲ29lEGa8eHioSSm{{qc \=DZp 5V40 @XX|rC`_xx8߷y p*OY3EǍ}oqw߳kۡBߧOFpp0k=Bm w(٘… cS"#0kV ٳ@Z<j=-h=Ӹ2@`[,-:e2ۇKjq]?/ 77y/x>}&[{cXYL6ai%QRrX5}m`3PxX3Gq]p*/(qOhi!]ksVBGiPωX.=n lw)ۯD$tǬGRpmi3.D]VxKqG2_??yl.^M>:40 aaa{d2ٖzxx{bE^?3UqmZ9ĴMCgn'yZga\1|prmڵEJ#HIy=<={6fϞpUaHYϙGuK_+:t%KxRݽ;m}/]3ĦFRպ-zZ1yZqQFE3Zu|-FuH٦ZI=b*ȋ=ƍS>H}A/0x):Zsz.$$ 'xi$ZwteVB-oބtJ=NDp q@k2Vsy^um-mwXZHG9(q3sF=Zw+uUҾ XvyCA-ʀi!4E@Gr (π?j^2Zγ u]%^πhyM7>!w}ظ8-adh.3sSSmE zKU[!WjW-`0໽RgàAI zuv]l!sf@mHR>3Yh  < TĀ FhfbU#Z/9q^4Zo',EphLtHN֭*kZg R %ӝF|m2R @L߹ " Ā{l߫dGDkNyԪuz;Vj{ B hi?|?Z̥9-z,ڱP6=A 46^R=msҪ\%Wy ܛƏbPg$Z"TBJK[= *_+ղ<4ܤ͋(QG$r̛ۨZ(%&7zΝ#Ы56*z_8-EJ6R"t5Q^QjK=vm$H R6qtKK1r;8JAA>LhcعS]P__l6c2jJ+6'-~n&02zw Zrz@ ߆L4mP@2sbcb}yX`!`2lZƙ3۷ڴi6/-~n 14 Z#溌^{|P@㏇1gc nfl_t ˖.AׄxDFbɨ(g-Kj,\ ]M7"C`6ֲ#C؈NasN<=p"ލg 'v}A7\_bk{ee̙k g9V1}GbY;x@{jZA/',ڭP7p֭OGAA>+xxxx_}co//~v?Fs7nX'N`W_GptaL&Ng]u)0ףֽ;VX&X>6g6>ܼs;v̡_p}5().%%HO_k#1Jr%{b˴+GJbbĖ'հk1=@^ny5j$ti9/YtO/gf{~zBV &&X|%m۶]-^r˭͛+Xm%Ρ QQHK[ |lq?’pX s૏bU23minKOKTLLDzZo__X-ι_(|g\z.r;~3"9vq|XG`X,(--6a]Hz bASSkYB#:&fحNnC?cժK5 >1m}6Mо},_#Ge+M s9 s _}|mudS&0J6K775~>2rr0iD(~ŔHy>l3rrA'%ݣ9\mˣÇ\.`.FDDDOڮŽOwSkD s#PXXU}ڴ[燚jtM,>o6|wNBtpisWgV^+ri_|5sk"֫Rѫq/ZdT3%4EP@ݏ}G]].^/[<5Irss1{V kYB; ǙBTVV`|}}'Uh۶Q\\=0ROӦ=?Ngnl0`kclbRf1 IDATXpF+lj#137vsjhR<-Ih9( a5!}?AƋ/ޟ={`Č#9ykYBM}]:wСύa{oc6a刋>}:WP[LALt',[6m }S > ¼y9>;=0laȅ]SɊXHLrؑZ#b6UZ >V[b }]ӾQ2t&MBhvgͼrGZ%k\vicf=>l+C@Z + 4BT2u.WibWg&T;Z.wsB7jVA|FL -4y ll)BPKyb tfEAbņ>#'`LL5bZMg_ω\0Qڧb=$/z H 4sFB?b6q6bZy[OFW" hX3،cX 5k4,Q-rM&A$Zw@* 8bA:jàtHeJ?{CG_c6v^CR>>PyI]" $;pU|9y{µ@m\99__:)hP!ᮐE 85j'8X6;Q-T3$@ U1AgT^-mb|ldDJ\2Bauyh1pࠫs&1FBOJ{-)P` %7b$$.+7=-M3) yH%YYHI!NV6o~ `!$ w!;>K ^V-A 롦@ko W,$Ena^n.6 DB4n*((fł1bQP^#Z)q|^[* Ɋ2P-%[3 c:WHĀ g$!KKOKorD#,ZjC!I_Ol|q9.UԢl5R'Z'U&t($_s7P[lȭSʔ 0 !rax0,dvZsdT3M@i߱M kN򅀅U+WMMfC\ulU"%@|jI -vXT}jgY$JX, Uhhhp^v\Xp_} sDvѣR3طo;͒<4r~#=$Z BΖ`5b"{Px5ϑ IƃkC?AA6l֯'￟05~;ڶmeٓZl{=v0pFhԩSp֎uiX,X }? CCCXィ&&.^FG@mЈdgg诿H6۷m|DZcԄ׿?؈~?6mڠO>M D$b W=jn={Ꮣ'!!dkG` Xl F#F#.\`@^^~#@kwhjjCBB#075?\9w3e@;gO!Qhc$1D-۵lB>Z#Å6X]Ε= nݯCIq :\UǏcasCcCrl?6m ~0714h,53Ќ<B/5pzZ:$'(FOC_M2rrP)io6N{d ck&9wTyaT ^^^(+d2 &ZaP[[PTԢ >>~AvmQSsI,{, $$,]Ю]{\XSq|١K1[7x{{[n;G2ۏڍcb}0 -ڵE_jmй.]Bxxj7y/ʳ{>^ H 4cA %-YaC] Gioo/ą^6`MM^0 PYY _UVVFQRYֿ;t0|[tt ,G?+jqS5b1z덲JxcڴѱcǫsFUU߄E~PghF57MĠK^+>@O!@״obT, ;?݁I(t/y7)SQS#|`7<;P[W٢_`:GEe ư+M7ٗ / v}vB6m/7//O0ͨA]]=k| zóÕhK) {S^G?߿7\o?MI3R=Foӛn >5|efbnjbDH-@JGzBA *+敝9s53 JRVY\m,*.qͨٗSU]jEuی+U5u|2 *߽)(w<_#sEb\̕T @ΨZLRbf$6Jۉ (f  4NA v\#-g-6XRLRi#?$H A>8}~JGlVbgL$!g tا H F3mt+fX PkD1bFq!kBRv#K`&nf3r3iii ! I)f Bl| MJޙPAd@Z ^%D@(+`":b0lX= =lHIU=% کlm5%-> @\%|PnŖ o!Cntuk=ؼ\yFb Ab]qM&2 T^Y8B4qq4hbZ iiW%qWl"!,LM|&nWZ)C !1ЊKw,dPŎn$'hQMe(H @H$D}TѓGH;l5IHh AbK5ZV/1R+w'F!aD"  -UmUL   0p 13%n\͔LG 4!A k% W Vo , $H -V]v( BJ @H ZJA t4RGΛ)'Z@H H$YC1 B Vn٤.  y t w>A:b $ AB( 1@ʡBm?AѺ!ANP!Ч BG( AD+ A $I]@A A } t Ab( 1@ʡBm?AѺ!ANP!Ч BG( AD+ wPV^P7A( ;?݁IPg&  Vz B!;?݁ΝyϡBmOwP/A($sg uuuhllm ]Q?미; /// :G,O> Ç'q}̙30zO1b|||W^yEy=p?.\+/֤m;%^}E~"ռ=pS1`WFE\>0 '1V!i=ڷoo{oׯN: 8SN,K^x<pQbԩ0aL3g`߾}8tP۷j׿?=~Yţ>>gj|ջ7:w/$~b`%a:e2a0XMbaga Fk˗l秥Ek)23OGUeWUYO/@BxDa XDl6#"<!󣮉ÇѷOo֡ ޙIQ{wzl*(PԨר7&W qK|&&uWsQbF qDeaDy:5NYzf~ϧ?KuUMQ;9AccwoƛEևjw):L&x,]ӧO1h \veRUlC~0l0xx믿^z)N9F@T>}P5mXlذmXL>x2~mlڴtK|l YDHN wSマ^{㦛nHܷyO>4VR ]t."|r<> {zol6|ԩ={6PWWYf#H_+**,X?~oѢEXnF}>6meBW1b$SQճ'vu?xG0rR6+ny^|,٩}Ck}3f矏z~}xE#ࠃkG-~ƙi?1ZBRGF;ߘ摷y:th|+ݍW^yL6o<ԓqP<#Gi~k׮E_>}5BओNƂCmm-jkk`8x sk8J)Ԭݐ5k7p[)(5УGL8ws=vV^j?9眓R_hN=Ts=u]cgwޘ9s& Aa̙x;u}3VF}:\u{ǝr81a2x&}@,]~{> .… hX@H^| ;찣p͑L4kwJ),Z3fLQG!ʕa̘1>8p V cǎu~n a~b1oS~PEQLWu: :5P l>0LG}}\veJ#O~b'4[w mp u8d`fsn'y$^nl+R*,[ ^xϙi裏!RfCouעf-֭[kB_Qx=\{Xr%6m5\֧vX|k>/o~(m. T׬e63ヒ Ɖ'>~x̚5 7nD]]nV?a̙3fgq1cjkkQWW/G}tڅGUU=q9==W_s-|A̛7{,<sObŊvW^BROjjbر8J~8ܳ'`ѸY<o>`ԣŖ-8詸 9\L=O3̜y=hai4>O_|O>]w~|0s(pA ;tb#8pgbҥd?p%`֬YPJaýޛbO>RJ> !~z?яP]]=_}STѪr; 0&e*7 u*y.TD0rN;N\xOr*1aOJ;Dy Iي\GJI.TD%roOsO̽N[;8O ӝ0& :7ƍ+:Rb`˖/x@}}Z{ -ZQG".%;jlI}|X@HV ,\%!Έeu@D5 "MhPҡP Vvn {*CPBi‐  i+Ru1Pf|A&wY@$8!  i+Q@!|C eB0lX@H(H z5C)B@jsF2)!d+ U^ 9? *#TF@9G裇NE(tP1uqpi?'t4P_B1@Z vaӂa B %QPV* :~GB:N@ŋ;h-}*iMf/Q2t&3f^RvfI W!Bᐲwh= GS4vnSE :^"QLXW=oRҹF_, $/'MBŋ ā3 q![iJTF !i -Ak] GREHJGc7#*Cqsb S XST HAT> :tq@Hg @pJݦB[j &CQ@wi*|Yݭ>rt"؁P tqAP9׷?7on+F݀~MR\׿F$.&\Z7F͛) |C 6 ! h]X5+UhrV!l/q@H'b -5I DAq~,"4_<y+0 B(enKBgxsN  @7p0U#"!0_X(3'KS[D=aJpPQF@=Pɠ13Z#w-,QB(: 3"P3X߾N]]FY˛t X@Hq+p\=8%%Bv' Hx<8)־{ =9Ay)8@q[`!-87?ǙvVRʸbb@fC%pR]]IMNܴ ڀ6mJ=6FDG[PJ,:TWcѰa a=w9*+q{9tfX@H( p-HrlwZhg@!W'`rƍ"xfJHH5٥BrA)Wf/4JqK!b`N@<1%e`sM Ā'"oGqkj8x͚8fE88:[D}Ы"vmt%X@H(;rJ nf!=D8>0S7lSFT?bqᘲf kBݜge%Ym7oHb\H;'%{ iaCP)w=/ixB(:( *$xj@|{zga558 7Wl2i*@,agJj&^?ğG]8lTWօ r/B yP/#4 {lSV$B1@KXB kH6br%RȑƊJ%RRov-ia{/'@ +}g<-BS1P,m0 . &P,E`GRʜ`}HJ)hA >樣0j5r-Yh C|=*oCxѾy) :8])!b<\EiE!0O^ѠB(%yg=jTbϸ@kС8d(O) q_wމ^t]+<+އ4!b++* n' x%u/X#ށ='콱c{,[y>MRbQ3qbo'~ 0ۜ.@[j`h+ s WoתL_ѣȝ#ak;jeCn#s˥2N%Krb z#@zy@ŋB(HuAn<| %674 dx?Ɓw]yQB(H-EfS rMx.@u+1fL;RR)ϵ8h4}4`^ )]bS iGyw;봁-00;))l__Xc]q|!RboW4,Xzokܛ !h`@pL-LE_߆/v<]4⟆8xghlX:>G*YyP߼j#UVGh: O -qocW 8%`E^[@D")ɏ^S(E,3__Rg]q4` B)k^y9y;wSxB1Ѝzͱ e=4hOPB? H[QLY,g$1=+.pC|"> y΀\!60$ICH$܊qRwމ aɓQ R;z/R B1Ѝuw+:2/ D@mK p  { "yv/+]~Xj NH;P)B!Ph C4zvwB(H;^HpʔO1Gk-c-ꪄ0GW\tlΆCEF(]+J8Ѣwmed !`\(\N`UW "'hj :W آxsDiU=}E f΋/ϤI[[,خBFa= i r D/\ZBzKĢJ k*i_O\YDHx-ŋ1L mo &(vN!L%̵>^qGz{V^tQS:t\58wҤM)z9}Z![0G>p4"3{FôZqoHv@4,Zl;{ln,$$P -4wO:+C" W 㑱+MZЕ60("RMGj@:FZa*)""DCC=1{! \A+` 9p0f#sj!s~/Sp"B);AӀ߳'zVTL HZ(|fHf!blSa ;."T՝!ri_Yǭz[)Tڴ?W~1/y( (Mi+RBC64!b0pynk۲c <(܋%m} bu p/!iЮ;ė& tE8( g*B /LFiZ"JY +` ø^t!tHYwb嗧:XAGiC~ j,y _NQ D %`_B)k(`區]kC0 i(<.,$P]p RA;Ȼ6:u` dQ 8 t5&褄JFRMȷݕRV{\s~ZMCB | {y/A"=tBR@lgkA`ΡOyHݟ@H(!h(&0T' EHkuFUR~@HH)!}?OqTK!y=v κCiTK9\s8  D) asABHWiNʗMM =Z.i~ѹ)+'SH"u.T!P fܜ9q@F,tLSs{@JP HNRR f=tA-Lo7!4A' ++&S\!rJ+NZ!\3-xLDЂ@ 0E3@:76Ʃ]7`A3j @fA-),900ZvysB(H`;@}6Ќ9S{G]\hߝ[p dZJ+9J9'\ChWl7!4AgwЯgϸv 4,PJ%gXS t*<'XEjQ, h 54`s}=~;FB(HY 㑱jTiĺ(<u :W$uMz]z)zVT- <6@$U@0Hq+5+nV?w.B(H0xL3b kEVLH-\_ B(ȶa_ _Ϟ-"Qj@vYKRFzO!|wsmA8P?7.QB!0Qԁ+3Bx뭼x !B!P B!bB!B B!B(!B1@!B!P B!bB!B B!B(!B1@!B!P B!bB!B B!B(!B1@!ZlaIENDB`mm3d-master/doc/html/olh_images/screencaps/example_dragvertex_after.png000066400000000000000000000354301324021725400267370ustar00rootroot00000000000000PNG  IHDRV'k3 bKGD pHYs  tIME 14si IDATx{eݘ H&L2KnK2uYeQVV7ª=`q,QV=xYu|EK Ldtw?SS]]U]U<<3ӗzV[oe|?33 ~:oW~tRT?d(ʔLS#bAtZi*eT,A y!7N:Y'|2r&%C2 ej㣏4Mp2 CE(TAzU-)\!V0MS@3{5Xjڴ-)zv ']2 C!&0 *-Va3UT,X>?eybrx9X!^ͿA<;) 𽁌Jh UrիW'P. e]/P2hLƱ:::|ٯqI҆ &{*8묳&źa}W*jݯ%4 acO =¶crUj[2])\KbKq rJ n*S^cɇztx*^\эk},>󄉓ayPgt!tnȠdXx*Ş={^~OOO(U-[} 6X,xR6lP:X&zHI5ws²[1',r)rk[foGwLj]XFY<݂jm3.+KR. HR:46c,.%/Hw?B:nIJ3,H S,[]*ox8Պ4M;SwkqU>{K7Q,0:|^N[[ܨU;{FdexMG\ϲb_LڏY]O̯beEԍ;_Yn~bٶ9.b8Kw_4:Z.kR,|zjTRfilweH #~dI5U1H_ S,8)U͜`XfLt[r+Eh>42e7aTR>VbՍnƔs>׌3Rzm,[}J2VxHT DZruȼ96HyX 1U~m7齞miuvvFK]Wۓx߶an~!@qXzg4#y%_3ޤKQ"R~߾rXr9uC:+ߵ?|^PnFNC-KSJZ>;uK%lue_U)6\Ӟ|?ԑk̒iӦ|.BGKy9vy{!*\ݺ>+jmZv^s׮/LZphqi.&}hj??0roO6oS@n5uWdc?OOoݟ ^˘mCtTXTM恢ԋOuKw_oy똼cٶ]3ՕѾЎLIRuilϘawJ*h" DJJ9SR^zKn0IRWy% LflY-w~K?)%G-,+F*gͪqTF nt ?=Cz5Gwҳ[y}E2+o5aPRP,NT,ROC ~=r̟7[Ra3rT/c{r:\I 31ЌTyFMټB znу*τ$[m4$p3@jJKqHqӓ0d6ܞuO$ libJAFiR䡮*2UV-WkUE6qVL&c{ԝs8 ttHcݗ>l ՁK%I~oreop;M=jwa5UeVUH+~y~?f\VK'Iæߖ_m̔UT#]ݶ7b Eն5)QZy[vc~4 fU[׻^!Uc A&Um]/18ݡn[m? tuI7}I4ցKuWXt,v56%Yգ XO,Ưnºg&V& ]pmyYeU;yfyZmbS׋wʊ%J}y4-#UBGjgMYn+KtX*O7oJzݱk]ƚn>M4̵e\(UR2Be/[>bU'`̫{-G43&Xk7`+'>3E6?;))KUPuYkqD1mмWnx] fcwVfdX5:?*A"\^?P,֎ϗ't;q˨ X<611甃;(A6gu=vy=ad\j5կV,\95ALKn!%8m~wZt?Ii4-:0=֪uY=c6U ]پyV//X{~hNz!٪!d+0w\wzԘ R!ԍ/Vך!9=kULzꪏ b|UC}I'LF'22U iŭ^e2nw %7NdlwOybԶQ5b(㫬XFwc1+-rSŘʨx\HQRB*8䃡ݎtWd&f%#H]b-z ϱx/%%G4Z/A@,Ry=bϹgⷑX牳:kBH>$ˋ/3$P2ESiP4dZEtʩ+ehv)bUO2׿$6b##i/(瞭[Ubl%]jTSLԯ~u^!ȅ u)+J5Y)BkK,q=@lެ >r^/}nN|]]ڥY~Ԛ5w= }odr9wLfl]]ڥYlެ_p f&լ! YTʉJHffrfϚW^yEご57I9s>lmݺC-oAYfsՎ;\\..Lg̙3~V㾽+Dsy٫7ݠ}v dϓ߬'9xڥ\.BqŚi]}ՕYz%%ڥ8DGx^;A^xI;v?~TLt:Hqw?4`7x.b=3ڲe?xs9o&]r%zkƌz7MzᇵqF7MOjukllL_kZbeoG?q}Ԇ .2nX[N<C=M'|2t{9KKKሕiNa$)JO)M>X_ˎW*M޽[tL/Z~6͘1C}}}kuo}KCCCZ`ϟkjk վ}9ر]G/]_|QKNc=QNxc "j06Gk~QG/=J̛}|޽[ŢC=O=ں͡]]]j "T~h믿N;vнOTJt/-W߯S3gv럾5]AO~۶kyzmd2mGo:v />(w^}_F%{]z'uI'?O~1Aiʔ4W_V-9j^)2+_< zۥ޼N6n͘1C_]sպԖϟƴkCDD\<ʐQ2],5оIi} a*n̙+0ŵW0tyW]}z{0 ]Ta5Tћ}~K;kgҤՀER)utt(k֬Y{/I>.2mذZ%uAk_1Ob%O_ܫ/_?E_Vx;lxNTkm}[˷4||z[Vꫯ-V۶͡]]]j>O-8]J-(L*4Jiܹx饗`k~^|I4s9ihYgwJL;wIRm2fΜO}Sz衇&w֯_˗^JGGy>>ڷ}UX}kt_/~q޽]zwiٲev^Z|CzG}x%͚5K}ڼimy=Vm'...6ƪh$:5jzz3VW_u?^/Ð!q&}iYk]]Ֆ-[xQuehVO۟ڷw>訣ҋ//}KZ|y/ZnNO"2s֮]K0 MOG.Ho?o?Y`ᴕg|> /@]~MO{{>鋗ՂSOmѺu78]%%ڥf2A婅=KuUWMfQo}ԧ'}iYkz߾]{3nkTA5`~=\=9s7OӟŢN}{{[93gKO.-ӦdXCDKQdzXJC-X *j(?,8L7t>Ogնmw.^..R,VV}N)ʐrkf[wiڵyz|uwwNQxhhv)xt:Uz6W-2lC:JGuT}ÌUٟz?,:X+u߮>/a/x _jB. %bI{5IDATcV ~ڈ.@%be5^˗V -Z}kFQk,cuO'[Α]2V-Kmh熇ձjU똴rXxl9g/8e@Ԅ&߸xٲnF]zM/Ï8+h9>`C[bEQ/t@[bŊd T'G&r9+VhjYNХ˹[=X@[HU˻[~pR?A_ XIU]bnobD vRucjXD ]~嘪Z#VЖru>.B/BbD vrU*TYw bF$P~JSʬU] wD?惊2+h6nlz7p:V

AW p|r Ҭ$ݼiDCx L) .UP!X1S~<Bj DIBU:@X VHU$\.Rܼi+@ >RU:GFwʩQʋ0|fw݀U288*2n.'CT+Id\%UU240l6+HQq\TZFvxD*Ī̈́YlHU5$s\"UUIU҄r}\dZdY E SB%$2F"@*(a`; VT%z hT!< l UWH]ZQ.[*V##|V_e *V^ȈJiuYPilƔPWm,-=< N: 4NR~+n/VָM>!d t,զSf=kp5XNǪU5ZDr^'n˫NVʏ;ڳ]_X75A@*@b%U7oj֥^@ikpU*UQP/)lo5Z cTA$ڮ##; Ue +@xBF!OUkd )BeIDM*Y'Oo8KU܄Z܌ ?)Cl6[u>2*8 ]X!UPK*}\V ;TTN VHU]$;0\+HU8X7T)j)B[gQjq"UT%.+V9g!>+ )&umݤjpp}b)UQyX'^Ng|Xۖ HUufr"qVqk=* 9jDfX^!V“oOfOzPR 0-b!,NdwMKZ-3~0-b-<GU$Zm=T4JPջ.fD'V4= HUxBJ^!VIRE8=%@+TDWDje05A\e-!g{#`T'TQWD@Z5UARoP- 7*3jY"K^!VT9ج\ 9'vgs Q✑ ku^%\:GF|D[jR7RRn`2?X]l1CUYgIQ=rsþ|\},2¨;X~_;lv kkc Z]Uaugš{fgh``ҁ㔡[yYFix8˙.gjUO'XEnp(]?q.Ǟ/ۯ*. Xʷ׋;V͛69 kX Hq?ZG$ ƚ*Q^.3= V-->=RwLgWpZo *U"dqMP؎X!S.RŲ 9FSmPDd|TFݝU^!XrebqFkފqVq{ *KBb 'XC꽈T%ΐBB|$UU9/I Ue6*64+rJ\jƀK/~) [8 UB^u6F~!=t "V&"WSˣdG݁~/сv0OaJD LBW sHd8hTU)H L`0E Ju25{{mJZ%Ls'FJ B3AIJMvbv3$.j|U+ Q$(R:-.iV@(d+QIV KUBժQlx rX%FpZ)^^e);F r#FN([/WB+*\.e9H P냑:I4*7Wr^|䍟uWbUv;'%h嶃 V/.U^.K^r'.@HƶDڜVg 5ŊX#Wߜ+H\Q/$QA::K]Z!Ɉ.UNjŊd0:ygCeɃ]qv<"V ̬U"&Y*WRA_l6 A*IR&YCVB ZE6՚Dt?D@d(WA$NYlH LˀTQ/Đff=q,';<<VU+˗ѶuSuV펥/Vtt_ t˩{AӤT+W*,:5NJv+'AQwI=fkuM䆇C龈s9Vr MeYY Uo̵Fש]wzX @ ^ RlI!ѕEW3UJS<.WD7a;HUD\ ZjL3C\JjE'jECde1RUU#'j99mVbA2-]kMݨXA+X1@XƤq$@4 D'RR)Q:I V\Od)C\y+`%){d*x!r%iR* agV!V@'ܨwӵF rU5uy^Hb18U C(pQV8 ֚e62dZOXsSrVBZ=wh` `E-{<ܼiSyb(T!VCUk5 I8jG* jA漭*H`Z@ R P,\B*%l =BO XqDRVo Q+^\8+ Y{EVzAno?D**fz ϶F˕XX$EN ]1+Fd8g.vȂ!UAzA\= P\52y^+N걇VH@Ŵ G sdėAAeYu&##*WSe9W}/QV6/񃤕uʖz?tWrN7oڤA.-\'/Գ>K;A#m*;}74fȊqNcB8ɶÉ6㭂 xI  XrpAHUT+0@ɰNAu1  5rHbƂ.E DC8O1D2+$+'U\X UU i.0*ITD_Q0ܦĪKJJIl4q-h\Y#|6!lY,K5ydc_d5KUD~2wz=N8Ԣ,ONvOX V{*` Yq8)ȝ+$+*YI!*" ud ʆ@+@u[- H\I6 ^Ode{\yT$l6R}X%HbzЌ!UAC cPɪdE)6/"T\5-吭d@,ihlQ{2w XQ^!UDThΝ5B`fڻreb+IH8 VԲWb1kee#WQ IV)C4XfY3~5I*urM4XjܲKnX9geꉏ!ZZA t& 9zQ)hN t' 07*YqSꑫzgR 䪑* .fR  (jD* Wj6^SKD!bdUb]wDIr"[X&XvɲVu( + Mf WN"T!V VdY#UGb|Ua+dUv U!yX @R + @@+ +  @L/|t?P}HZ9Pw s# YǤ:QuW7d|fjEOhѢK -]شKSO+/ .ZTn{h g1/  %"@+ j<nIENDB`mm3d-master/doc/html/olh_images/screencaps/example_dragvertex_before.png000066400000000000000000000357621324021725400271100ustar00rootroot00000000000000PNG  IHDRR'bحbKGD pHYs  tIME /(2?ӏ IDATx}՝q"(6qMܸqhd $xk"5J&^dLuM"n^@tP ڰNwz{^Tթy恙:uw>;N)+5: ~ M B!H !Bܑ2PU$I(@Xi^ziS ;`Xp<BGPEA*mUUqiAQ"PrD}rɒ@v׽%LB!Dң*N8a*ZGл>$jQ?O[G"B"uiut E:|EQXBHIzyn>B!bԞM>W+[Aa?a yP0 cǠ0X@" mho|~PI@UT$@T EAPnYZ#TP(-L²WEQ$  EUH&ʩD*<=we*vƠm,Z>v Ə ơ}\+beaYD϶Q`FXR|V,mHLᴏt"_PH&R8}G׷ #FL(bD"|>@bbNH߽L%Q,fTTL&m%(*ґqZe(@"LΩ"S,EUUE# jA@;#=EMV@\GS&O@>Ǟ%=cH$K.]Z.KkM, 1TJzi_)g2,m8Uze)(v8]^`66n4jQņ7W5H@-P@-M oPm2^XeHu[Ďv=zT{>G>Ďv,LC &vWD m,Z;_2\3<ϗzxR) U_ZSA`S&c,fO 0v6oRVnY89X/,KbSQH_~$ O h{%S2 ulhl6kZMMMbbx&v@vej`:[) Z9}^nI]C"l)+F]ю{J,,LD6vD^2׋ L+eihǔ'6La߹b/k Sz"TケWx@%ie]ejҥ BE(p?!KRu$~Wׯ/upyUuַD"Tꏏve ܰEXt8-ɔ:7e0p8@icxs]y^Dh'Bu/oS?ډ7T*sf[G* XܕTa)MeJ^luV/ue/K>]Zj ƃv{*}NgCr`;VhkK5JXYD1#,^UYTUx'N(^FvW_{ͻʢDID5r:eۯ,Z^BU+G{lpUd WFpdyRR7/%ڲTƴRz-(ʰr>6CI9@9MCٸm|[zFƟ۶?-+ `՜3 [c'BtYHQ@%6YT\S.2U AW/zQ"dYd9F:3pyqm,#Q{fS4@).Eڲwyx'qr=Wv}ʢ nhGS>&Qˀ8Fx)kIumu,Z&M_)Z)`ytToC\gm?$hnnV=;|'{^]p l5,bXYj.T<ep;'KmĪjU .Fdʨ^sf[ WS1A#e7^:c挍U=&q$D֭7Q.W{jRNs g=bA~l(4q)8(`Fo&S:˓>JxEQ8i,6U,8*CM&JE˔6Jy6@?{8֜Aoj8 huA?,&Sc6hh;?\I8E 03eu]mv,>8a2ݗmoآUIdJ-'Uggj;hXŰsr̦+0ڿϘ~vgDNnJYS3 ,KSS FO uM>C>跴8:b&PZكEZpY2ezt9)K^<),!f !QvŪ"D,voEKVD"ڝc&7IBI8j@݁HHl穽FNM«'[Vݐ~e\l?_sa(s =P^b _@lU/U2D>_dI]+Aedi+ɹzg~L#7(,he1Q*(Ȕ6Wt_(lзkȴ,A0xm8Q=Wu2B9HyjĨwh>xn~FʺWMjW{%e0:@>7T/F60aްcJm Fe{Y7e#Sγ@3{z*& Ved(@Gd,Kn=d^R) 4~>ˑuoRvLS{v*f+10D-jX :u-CYV^K(f #;JՖXtiWx1>u) Uy@/ozqO7. {jΝW$j$ĵSU/fnV/,K5fOy%3FeInBَQ=Ţ/㣴 b޼y8餓pmĽVu>=ȣ/bʰ^t-z)?勔͎~9})I@IJqى{j;}dX4SXe,~]ŧWĸcx2*~3rFAEk'; w8o/m, ت^*=!>H٬,J$NԐL$QDS{vaz߰pډSe ϰe1,cTYO._r$ ?>7|FbLyve ?+*PYj_YQ(TuBx52y CqɻņEJk:ng IvRzq,*N U-j&B!8S{B!a8_t?@vu`<B_jYp  NB!$T"eB!6mbB!ukB!čH7kB!& V!BEB!"E!B"B0|U<1;v"<`XLE ǎ? P +)j (JP(I`)dA@UTH$PPR@"(( Tmc*0s %¸$Ky(RnZp+^|%0 Z}}cǟ+—X^ j14!KqIXxx2M3F"҂gٳgc;v`WE_s_c? Oy,'\#C?W]A*CZ>mm54a\b\"KRv؁˗`^CD<ڴL+pɲYøĸDd)HE(B'XtLj1!ky,I9KyqW,Z'X[.K1cføĸDd)ށc 7vDa׮װl{Gſa.}ϽhjjvVqѣOM_طoey2.%IrŘcqb k'ax1886dA~'܌1c .@ԧ>c=cǎŲe˰w^pcܸq3f n  < wf?.">~O_ /?ٓny~vxZP(088bhd2;n ޿`wbs>Hٻo [FO2('L&<ن?nǛu}+믿;wSNE]TUW]7| F/ش<<^xl޼۶mo[<#>jzufxp"W_k:֯_7G1Kd/`zXpRx%%%oDJUK}H$U?Ţ1>2bQšCkƴSk\V58<Ѓ81}>񉳰u6*&vG>Ďho;QQG?9>ϣ ׿-[T>ꩧ|GFGG. yGӃSbʔ)Xj֮]+0ҿ ֭[ph{93qA˿|s3c֭9-NjԋKFC6{V݂sfa /áCP,<<mccs'e_Dжnۊ7 {}{oG"׮s7neU;{{Iӊ~!\]_L2^ߍT*>vՠOm\o|,ˆ#*9r<:,g… M T>?ꫯ `˖-~jywqV~?l6+ֲl?Wo~nyc;7߼ `?\㏟*|Eyťuc??xSL(7o?wqWbL>ma\b\b\r[#JUm$H`„ U}w0uN8zJNϟ|ҥK/c-$Sdc7};v^Ǯѿ-10.1.1. #UTuO~;n O@Q[n9|juiki0v܉3gO?[{K/71k,Ut=WƲeꫯb̘1'?Y4u]bN;*X=z]~G?QE\z饸K}Kc„L04^q+X|>KbԨQ/B{x?ޤ&DO;؍W\aٲ o~̜9W\ika\b\b\r^cV]77wu;GVŢD"z5Նۋ_ .\`ջj5rH}ݸ oL$-̘={6}+V`ԨQ8sqQ\sUs>t:l届KqC+V^+V^5D"vWטøĸĸ<"T @UK(z)'|2XvqQ}x70jH,0.1.%Yc)R`>Drxx~:x|_oݻļO1y-\a\b\"KӉwǗjX|)8'OAkka*a\<]{DJ |_\wf¬Y, 5Ta\b\"KRM>o"==,N69md*a\<"ݽ|dz<|i(dz'NŬ X2qq0.R/>'FL1/fϞk3f~w*S [y,I!Fh ڵ?bex ԓݯU@%¸$KynjM~&IB!6I !Bak;v!`D%.Ytk `*SKY⒥HijEEB/̘1Q)|v;_3պWshZ}vO烷۹`u?gFDFp!D6!чrB!DWΟWoۆku(EB!qFW[ht밂]{B-r$K`FB!JLSz-Zкf!D~(RBD]?K.*qF\r% EB!(]h|A|AeHB!$tewc~HB!EB!SqvL)B!BwƍXb+Vp]F!BB'SNק=W;&J{-)B!JܮH(3B!$2%R´uR!BHB!DD%:(RB۶5{MKx^\ooۡHB!$r\9/BH"BH$q;I ? Bq EB!"E!b͢E=1RD8=]]Ctu X)NY$09"%J[7l@&AOWW\Bb+Qkoǚ+BEHPUoNpjS:F&A3tuUdJNWƺTŜyםmsQDm;ŇJ χpm0e*ۿlX:m(S%[m4۩7I(mGj׳fv˱ Ʉrx>c;vN2ew#EI]~KEH4ѺN9niH,B#Qz2L%;E") -7)J+D"$\U+TNDI Tz ꄄfƍ-N@!tR8:!fL(T B&ʳgpuB gvG@RHE*f5ͬ!p:D5۷#N33E"QIxY*B' ]PWDADJ/U6` EPB"URJBŁ"E(Q!*J!Tԅ1؝Wj1NOsDm;Nd*|*0~*m*L&kIc0Bwev%~fɋI%kJ;6Ql8ui'PqB(Ye$P {L0bmӕ/QjE i(R# Cfi7\\e1x(BOK%vQ0/v7e*HHJe%'" an )T2Ka* ,J@o D'P2 S)DN~ DNQ.5bv"EJeI>MH093î>#C!W'6GJ]\W"EjǞ.쒾%E2D(Q˩ݤ{Fe*l2L"4l\/¢./N_/ oSyg:-KWλ]K˖)'°[OWe VwGCOƳO]nؖ/גV4^_rd؎)UQTU]uQjӿ\Y_/foZko7yk.L_>/NG;sXρA @~zƧR-DNVDQƈ kmzSN<5Y*돍#B/25^KlS"g2*}7v'y.!JlDJWdkoGW(RsJOeʖP zԎ[3H*2A4Qc5 (Ա).ԃ(ul DvZ/n˴;E$mHR孴Px%*|e^L?ׄ" (f%zD>+M2->H:Be$ R(%FdmxM$dתXy,G5ҨHUDH Eg2d f(R)BU/sUB$FdGJ˜yNQ(S.@tfPks__CﻋlhN&%y(3i JHjv,L"Y=̠״0Ed^Ԡ_nG0E*%4STo Uğa*# -P&Yʀ 4 ɔq'T~ P6}-VmTDQ؈, oP%ۀkbmK?$]}Hd:< ]g2\{mކTdPt1:Fڶ2MR^-+RG-2qz uWRHw7Tj%Aꪼ?0󡒍PmyQf*ɳFe]4Y/z;^a6{ّ\^dFc~>YYs6*ص"d/e)Tn<+17V<=HѺIt:}-n.$P'Es;lRɱQDTD(a= VJ<ˮRQZ)$,2eJD#迧ve a#D!EPV>~ncE!#7Q.QvEP/Gvv!lGXH4%E*f!0$!NdJ?^B(R$"26EL@He*Y¬T|"E<(ed*fB5g&dAdWl%$nET3+8I!q) zp[ىL&܄%{d*Je&U=]] a6E&Ht'x.Teʋ]&i0Re|z.!i(Q >IdlT^.NB :,3"EF>L92#q)lx He*b6*S"E$("q*ٳSQҋlKAdx/`fP'ĉLȱ%) L\R=8OB%Sv"E P*B"Sl# a9N<(RD'{]=]]d2@@B&TA6~lx)Q3DfSy]dY0:!e٥G 3R1) fL/DE( (D=)J@r_>ϠNB@t^-˥)R8wADM8 I璢H9a}zr=)]Τd2LO>4:PMTdKW{.ϩP]KsZoW2"v2U1Bض:;}ׯ-!QߎaUwzݵtr"u"g,v~ϫ}])?(F>}+l;^<ً5kՐ;"2(c`nK_uWo[NluN'kIHpa6\ƣgP'aGDHHP?PDPn҇"EB&Ad $2qw"EKTF6bT /%P"+PnfTc2ڨT1KEd4 ҫE ED' U#2L_B$a(zqߵG4~E)iH)Sz kKY`)J0a6$xnݰ2e*TQNf(QD:1&2Twa6"_P ǚBEdڮ>eWdQ(RDF묉2%ɘb֑IVvv.;EE*fWf})S2g],QXIGtuZdN- koLd*3(yaV*cMi&Q0#(%*2EQ3>֔(5 Z( "FUDԅGzfA*Jk8!'vM/2wNY`3RlTmլTM"q*N@(Rd 8)JLy=vY E**wGM(,"Eldp;rcJ%b$Te(w)")APJHL"0( T!d˄)QBE!)ZR9^Eq#SG"*T(!=]]ww]FB)b$EHJWY*lPQB%*;UO(Qfs54OQԶ}AMlt[>5um']^_3χplgv!=@ vBF4 '|.TuNQ+dF3%J!o}}DN"JUsyܓoNdLNA!^ȔQ)BJQ4*cF%0.BdK);_^̺ABq"#E!B"BHB!P!B7 d)?IENDB`mm3d-master/doc/html/olh_images/screencaps/example_edgeturn_after.png000066400000000000000000000103541324021725400263770ustar00rootroot00000000000000PNG  IHDRXbKGD pHYs  tIME'yIDATxsL &kQQD$Ȧ%UwXg7![@(ie-K>nIBܞ}NO?OU>ɼ~VzV AT' A @ @ A A @ @ ⬶>OR[d3l.|P.\%K@I) |bA {B6F@p#>P"җ|nTQm!ӐN@V+RIeDp<Et8HB]?VKx6|g  {X9ASm`[b9 [[[5"WY.ټ_{Mp*a133ŲA&Z"Zy   ŝp*p& AmsliiF# T5$%EpApD$bH'&H@,n_}yD{ NLAs(_L"AZ*:ՒY, ẗ^y{N" E|}j jo/Ր8;TQw/T [>2Xd嗑GxZ*:@U.*u@j)s8EҡK5$.p"^#8?DvujJf\*UCbs541A4/$" Kly>H}dg}Z(nT| M6{w߅:JfS IGX2։LbKAM<@hEƘݷ H''Ţj'޽eho!˅+ՐE-Sl1UкPڇ1w6f{@R48f ukgzƙ]Z3q-VBo}JZzz萒0.;p` *r&l>&a[\=x` k$kp Y.2v fGedwVG5[~;+3 @ K۶m{nxxp8*mGҳGO]&Ep:uoALhC&9kSp X nu-R Y݃'pnEs4fiqZ˚r-ߵ,9|p8j0@Hr[z*5.HCX7Ah$A[&\,_ge-#ssGAteCv1~Ģݖ<㉼;G%dtQ3 +6^W3I ȿloo_-Vh`l,)hce{zz^\v{$S!d/3 tAxgҀ!π x6m%=.#{t}6Dj; Ax^Iu1瀈X|qPC=luY?:Pebr0f,> [ 8 @L;Ҋ6¨?5Hgp hsǏ'WAiiPA~dž&k< ;] :7>2Nsjjzj q8ҖQ۫<u㒈j& =hm=P A@Iww7J&>T`Was2g/sRc#Nao.tq ?D{EuDF/^Lݓ'PQ0ǙLg{P1D:!һ#bZִw}D;yd']"<;`]md2֏U0255tpgON<*Vjju8 ] 'NfjpD!Ʌ-[p[ڍT(F=*z񎟶eU6EHXufՍ㔹֩^+=wwYd{"dE "l!wu)$?G7 yN5J r3NG~É0=J8! A[8 *рR]R=[iZ]'N0b ^qL*Tӓ 6_=NjU4曆ǟߎ^! @6<,( <-Sgg'!e[eՁPi(⚛K]zlsS PidݗM(d,M sssB'vm¬ 0ybt ݋W(OsGӭ$J#r뭷EE%2{{NEe/] MraE'6&/tXa : Niܮq7*q" 333XIAw8dAĩ&CdVtXAn T8\0VGR{u7-Z rז.] ȉW2$ү\B%]Ehˉ`p^[d cXº( "Y_n9HGj@ Aŋ* "CI3HJb Ndeiii92\o X@ TX@QTX@+ 8 @@@@@^@@d/D>!3T A @ @ A A273@[$IENDB`mm3d-master/doc/html/olh_images/screencaps/example_edgeturn_before.png000066400000000000000000000071301324021725400265360ustar00rootroot00000000000000PNG  IHDRXbKGD pHYs  tIME%wz IDATxoWOtF DIi ~4I!,"H yO:0 6``x%aHm_v{2嚮[U=I-Euu~}:AT @ @ A  @ @ A  @ @ -K^'2ߞ<_[y}Vۛ3kό-=m΢?=[ 1A.,/ӿtt4/Vg:rW uO=|G+Cρ>w̋uȷL/1L>?5E][@tH3=pH, уizxEa$^=G33pM.bC2 x>3EvgE!q 8;K?3p"W?O.(F 8$a!7=fYs-VTH\P9Ôu4b\*@|='pI@,MW?/@^H:^yeY^ɼL;+7>I!95Y߿=95Y߿=95Y?AnM5itb8Ajji "!\!!".hP,pUvf -iXa $fE+tvLhXRK%k\/ &@f $K%7p"=Z٤|L 岹Lw,F}~ބvaɄtH\-˴TR"{-0V@jRB.,lPPay G"1YH$.(p2VVI# 2!qUnRV"iDаTktb(d]}ʿZjVVWטZ2VH\*UE!C⪺JZ-5"V jZQK 46VjT׎M.?\K:Z}4AĊ i6!pYN RL",x:hPp 9Ϭ0Epq @Md~(^KbS*> e^r#=uZ9z IͫlKoP!Tpa=tϞ=KDDWܹEQYߘ;v{mbJ.n~wp#ApWM& M=mN7*~ +1 #WH4mx1VZ zN)/~;e̙3=HIAf; yw_ղVp =SJ'x]eg8N>mjD0-Z% d-3 d~}c20IaʅdXW:urIZUCݲ(ppiеGB:zԚhes[fshDhR0DArIk":>r2! 倨J2r J'Ny"e۔ }\Rh2pAD c4D7}JQaVꖥ biV&GOzҕR ·~2zYp`K٠#Z%Ak 5rQ+`R V8 & ڛb *e:[/N$I?EȽI?rFl8b$t,ĂOoiVp+,awڤ =HX[\~ƐgMu Np4$tfee漄JVܟߵC98Nh#Wx"w#ŋt~Uk 3AGGn8u4K0i_&XU"b:G.]zU tZڽ8tŬbH5[_27)@xpX&ü>66uWFD}a0oR+` JDԦtXQcllhg;ɪ,4Z% soo/$ݣGK(Ǖ9lCI=Η{c|TcEiT,i{n\c-"SXD& » pdؤ_|ux_ WL4Y٤wJnRъ p4eGDG8ݒ^{$ٜZ88}'ad@ڦ7IOOO*& .#^5zzz *CF ६Hj¸mƈ1+qVtGd0Py hbb:n/$PCgם+[lQ8  &9{T!ٽh0E$c#r/Ґwww8ρsaǍW:ta!dZMLL](sYWWYpF5@p9c#jR *ڨ Qv#,Ph]{8H{Pww< p/? j̇BE,o߸q'߿pON" GzCGle:H"M=W&9Jl!q8IE}Mڐb_"KC7khh5ݻ՜~J2r8 %dz_FFF"&{! ֭[5>|H\.*iS#2f~~0$zE2mddrNb1s}RI9HɵvLr+\~wA#YZ䇣]ݻwKqwJ(Z(٣V^8 $d,G/9&?!-#UvB5@DmkAQp?|w>D|֛W-#ǫPvvvM3F޴!ktvv""c7ת>=Ds݉0p'EM@Y tq./{ q]=C <ޝ$ʍ:ܹS TnɀFZwWi[w؁Ӱ!'nd?zA[k@ QUe۷o A:@D'mۆ# +bu!VlݺGJgj2iej[lAApf(E+>b5s! h8 D&yf iZ#V^M6j b^in@qD!;"2.  W; @ @ A @ @ A[aHC IENDB`mm3d-master/doc/html/olh_images/screencaps/example_faceout_after.png000066400000000000000000000261651324021725400262170ustar00rootroot00000000000000PNG  IHDR|bKGD pHYs  tIME 61TW IDATx}uw< `.1 `mVJC;$6$ɟJTR 6!$^#@/$d@H:tzڻ{gQ睊33ggf}Zk۶͠ը8tT@Q ըFjTH5QըRjTF5*T@QjTF5*T@Q ըFjTH5QըRjTF5*TըRjTF5*Ta~n V \+P@z0Ӷ(8E?Qeyqƞj0:ZPµ42 03QOV_|D6 R)K({81sgvv=PTw`^ǢDrM/>`@#&b1:ъ"LۘjJUطa&uԃ5@c$ KLWr;1jds+f2ȱqDʨkX|>*EJ;+S>%?qWW,n4RPԵF-@Q@8R䶏1|F&+& (JLcӸ+[%f1jTB >*A21 .1ILbAb_(Lds|@κuXhHT@´<: ·@ XK̢\Ib&kL㩩Q*d[)8,(88s0)vDqH 0HW,]8jq vGOgOaR͛ C4k5`1,[Pp09]!d˕yEA!łI;\6`XTL-_0DVK#SEtpnI!1JΏH!8P#os(MMOrS 6ndT)09Jk̹(I7Lb%؈q1LI;ЊcƊ'd-[D= Sp8\Q@!I*2R,Cs%5`#XJe< V ^+&?BKkQ>)QuJu밬f3gԃT AøD`1F%e r+/A)((Hϭ58|/qBqpӦMN۰g,Zf52!\[?Eo3)E}H)Cb*=l$Qa$BQk߆ "rhf,IaM9UBKF8@VY>1aCoK e/MfgT>g>Wo>1pUN%92[pI/ndPLr0eEc$Q`q}/Zw׭*xkbr0D# JXupis/s8$(0/" XP̏HN+5eL(>vp$^=p'&:rpHE+RKi Up  ]Scɥ HDƸCЉԲaW 2;Fc֐ P (\GhW\QFbX x&*` 8y\ }ԏ療 %.,*zܼ9-'y.('IV&ؚ$ *՘g;AʀVEȫ"Ufd1$O%UMX=fr q2,5ǝdni H-c 4DZmڄEzs0IWj :7EQ1].&)5|T}.qwIل ҂0ĢZ GS0?3L$+iskO"W^=W%Ux&Tb-m($ d«8P2 0dC7WkXK܀0uRoӔ(W\Ɠ?w@TRCEJNhG̊ ΤaAkd:55c`հ(*ؽv-&x@NÐ!u O9SEVQYE;ޗ3OXD7LbE:߲ȠKeopEvph8 F'P\l$vq?=K@MZTnMؽvm%5_哓69Jz UUP^V9+Ew% }yL,MIk3DiPK$In6u::SA# ḷZA4zri`@rDu,*ӸEI@Z."bdN4\VnMس~} g-Y&/+\rq1ag"QCfp1Juw0rzu-'[I$ yN5Bc,c7 4aLig( FA$@1>4BˎIQ"u Iz7y =plu,c|Qfr;e*y™A؃Yb}I&kK](Xf ab,e XkƤfXhT 8qc6jٓ33_W[{ ޙu9o]tqs~F x8H<`$-u =,qI%Xu_D̓c 'k>Dbe2b>DRBY$h/-xw:19+B̴u$` \IRרtXKR`@"zW H<=h3mAȫض651iϲJb[brtOZ鲒U:y)0X$J:+%T p8N y\rI?W>PԎ@Yz7V ׬DH[! pL )%J$V/ |+qsN+<ʁ$ۤP0H-fV@q|͚׬A?ЕF>|KDuOFfxQL:y9X+ ӨH\ AL"ԴF# o} ߟzX7m؀Z6,(e̺45#A}=瘂? w3Q{( BL d) >G%COC"\1W%!J9yEZ"@q IZ7u;zdV8,z̾FMUZnwّ$b %gt#=֙H 0IjyV^2ONY Yh`e9 $t!m\ѬnЋaV0f) 4pH-oM` 4b^¤d2%dSz[ªe/ 3H'Ya)Qg@I}-|AnkVHI30:3R 5irW*MѓT>)zRmC폸_$B>6gDa?iO/REiևlPg X `ʰt֭8"s| :ްo:s`wMI@Z>%1 `w3RXĕ#)+[',F2 ⠎Yӟ\CdS^!Ie.5UaHW1)bQ"3:Jqc+x~&qKE;J"Gh]ErױR3R["Q\.'hX mA~yr#%H+R7(Vс5oW5e9J˰+w\4+:S֬9}&jѽ3]:4(`W@uNB$ e'{n$}3=zHWC|(XYREBOZiVmGBa8CII v#GfzU$Dp%,H+ŀ*e't7 ?,1ɖCQ}Ar# ^hqFLtzr0 RYS9_B30A V0˰Lnf)"`nSL2}Ҕz=Wy J?_܍IVi pn /J%<-q/ 0ڥ$=S0þ4ژی&?Lz'*ZAKL̜ygaUC+L"bU0}^{NR<5A eW&On̳K%}nD7o)9<R$ 19PPBC0.e$j8Xο^{Ͻ둽9H6|wA:a1ħgpb8CVv1h{R/UJWm3xAё;ĒFu4 J5Wn{6ˁ>.TMeJb񘁁=Y'2"%J⸳m#c٥En1ncSSH$ ]҉{2ٍ WșqVmqF {AeU"Ʊ|'ccጣ [~ +4>W,fqpJN—d-BL3T%rhG@ZO;)}fDE/XSX8KH,1t3@^qIkQSc $$柞$byu*</uwڐ&jԇLDo!%lb̲T!JNDWRRJ;$6H2pv/1`?6=sEn7tȺ2=>w:<|6?ك#f<\uٜM _ !SWQ B}4`+h 1czMՁj]~{oTlamuSO@̏}'PÿJw0}xfu)ǂʔXlD+ϑ~ co81h* 'Xumv TQ>ͤw;G0tx[= 3goSgu6ɆF y}M7]Õt(DŽK!IEb8bcpb?#Q'"IErgP҇64Xgů~I]Ĥ!m#&)o;Lyg8u)z3+X-%#z;a{J"U3Q(L }M8#X(a$M2nG ;m4k5xI4k4^^YBDSO`XYgNZ:X3RCn%V0$qȰX(>t+JCt>|qLZ=w482 K$jTu;>D 0D-P#&طzu?f-\T2 Z(7ބߔ9 -cn$) *c%-/Ic0SI,9@o DFQdzF쌪mSG9WSW5XNDҸF$#O#at J#]Bƛx98/vRCݚy#m,È2_slzuəHk 9K$kYpo Hvޠ9NAJa`QBNSŲQיҜs$gv'xY6MO!||(+)>H*|'j54IJ2+p _O^}55gU%+MtAek˄6,-(w%_׈$'Q]s t3386=o2{ ׂ~i0-sx::>u>J^z!0]uS‡Q(jN?oD_DEI3(mތ&&j5L~+ϧDB0 f6'^aG:.aK1R2GRϊGQƠpX}{d%UH&_ѫ?j}SOxkUCi٣B:O'iքSg Ak)H1R˜I-8b dE](Wc!"XHwP@@,[z?#-eteVq9'qQ;\My(_yfێE MҨ =PƘ@"ر tW_%/IpDQEg6}pғ w?c@{8BYdwoȎÇsR9ON?w {W:|XΓ+W}*6b XpvǦlLB(84no]Ǚj=F^~B#Y̓+^ky GGuI*x/8L lK~;AEx磌pK/LE8>3pfGIe2{6aa ~˙Ǘ'Q2y߽[6>@1?Orۑ#x3,S1T+"W6rt믧 y+;lAa2,pnOyQc*>N,n40hZHùI:u#R IDATx?$ Zg&;2 7I}*c҈"-'tORY\h> '5kxSB2b\fI8jNJ+('IJh8  9.w[!`em؀&&LEb @\y%5e^],`ŋO\:$D$U?~[΀扳WꮤW+ڿzu ()!uVS6> q&4`MXh`2i4gOFsZksg&yhɮю+z a{:ɡσE/lcO}*sW,Ê}`GLI^melj|xaЃ 0`lX-[^GV֍7N{ltK0>K.ɼջwg <{9QCtg?Y Y9\-ECz#\wY75#_2۶Yv G藂ag>{t]3eҿy\<(_Z{q&AzXQY8⸳#Rp,<)%|OwXT ]K{:{eO\/^a, ;>\~#ɢ( - I>p0ҋg?K5]ZbYD}58z]^d}@k8LTvl __x!޽[4'e+vܰwo$PٳVߟYDAvص+o]~yHav9{?#GYRvAFQ E#I"'=( LbYF/WJ$cs۩⒊([r1eW]%O_{ǎ9O4[QWl{î@L-HyKqoKM|!aOLˋ<y)Ki<Ϝ'PR[E#X6b|P"VҼjndY`|e z}vjȶ+unDn\lF݂ˮ@Ziv}7qݞ=1.Yw Fj^z)L;D{ '!RAΧktW;(tp&L6h*D#!=P VOH,OZ(ٵ^R[^|1GxĐ)W\TQ/X,dkĪ;EOR$H$`oqo6smCP4o|DJyM~d VczuV,[L6.pEr{֯ǢdU3 i~:ɱ}@ɴ/M&wjRy}YrZzk4nuu-eפ{B5006nD#aFv؄ZkLK?sK3?r𪫰׿JR׮OJI<gF ^mɓ>E?<-2K_-ub8dgqGc^g2 41J96OXA;)zlC:gPb154!cՠb!BG,_1gq3 =*Y2ד.*9X.f @ƀ]{w<ݿTRl>OG%AU&}qǠi/TFl|8A gp a}LT2/?NT2/أg1U r BXهMJ{p *b`]N5pTs  Q]K ը|e ,dRUƂb@qJ(#jWqIENDB`mm3d-master/doc/html/olh_images/screencaps/example_faceout_before.png000066400000000000000000000205501324021725400263500ustar00rootroot00000000000000PNG  IHDR|bKGD pHYs  tIME 4.rj IDATxy՝ǿUYa (Q4./qK\č'˙Q@pLIL$IMqAшO!Q48;߽֭ukR]}?}w)k &L 6  & &L@L00a1ab„Ą  & &L@L00a1ab„Ą  & &L@L0a1ab„ĄFE«4z4,,X@>05AqPsݍ73qyi]h -y,؞:XVͻpe#؍yDd14½ *@U" Vl 0qP6wA!Ԅ1{W;P @qGh( (P`X^H@r/~ nH*0<^(\0xհ,|Ze )VTl>vl>(|(m*VQ tuw7@q4S.\,$+@UQ!1eMu, (@7k*b L91O=մǥ?bzl9bT*(B`xԂCHD5-+$ZA]w>6p *"ʥRy"TV R =O1o[g1\TEt [P@ފe)ٖRpxjbcYT*ÅBTV%]^%(ccqjү<nJC*t6JR\@P-H:U cj?{~bm>9*x铧$P~ҧR8|G⸶{/R3f`H۷Q(-ڜjǔFs%CIy<&m x#V*EX(U ʏ@WP[0ͲX5 fU2%> QhP T3롇n- gr\0`CVPPܸhQ{I[YpJ(J{7 1kV\U@x ImL @T;?/,d…o OETŐRŒ,'BPxePpb)]{huH{1RnJ3l3 o2Em< 2^ʐMO . :o"@j }@{h y鍊0M*p pnT֒YԵie-"-Hk;$iUA<nD>G{ -IKqڴފ%' 鿠40Kp0IJP␴сޡ"v--VEI4&F0Ս7b`GGw@ ! T sJ|LjiI@^{ Csu͸%M$-b0d*n9)G`L94^Z-f} &x1@\`A,ٺ bvO8lzpL G.:y $%*b+}cdӴipg1|F=L4O =dSeESMt I7^*29uK*-({RHV1}nob3zBQ .S) JS%[0p]~a8wW[ʍMl1#Xԙ2='[]zvԶ* "Ubi[-3؜:X:BGF=Ul )MvV) $)|\@$uuaPW?CPZQiJ[Ko~cZQYfp+`A }xZQl(vvv<"_W$ 겁H>seOEeb_!ӧcr-1ICXW FA$e F wgBHyT}?Au%)fBU ]?\. -(AM@r ˨G]bu H;8;;;AK1AP. P1J%mIQj. 9;,BCT,{1qս>ثoC ʠ.> PU) V@Sz$U,/ P\{-F﷟c?z$L@k yj`n"X 㾯|c`qs73WdQ Af7*ʼ9 ,6$iȞDR[2[!?׭ ҧ,^XIU[7 G<i^z)u!Hf✼s-U&Oƶ*W,0ܜZl 9Mrl,TsY 0[Ks,jUf$kde5Rjg 0ۨ3kt,eՆ$J->h!;J$_<|&.*MيqgeHwbRABg5 ,n ̮-Pb/Kk4 ]O?T'RgCHt_gEF@א^BgP93X\$iYԊŁS", L 8IϫԛF"\ɐ)YaiNZht)+Ԡ"O }9=gȪUi3bR9ʻ[="lߗ!SQ*Ҵs [nnp}뭑2>$#ig*kQiU>+h޼SQpB!f tpJ6Vt-sncUG|s۾]D$´72Gƫ&&=+M}h9f1FhF5NMП:#S&5-o9x-ͳHS[o˞^w]쪫QZ[Mjc/ȸ'$=I>IS*bqT8FUf-sf6͞Lq@)`Q]R"G gkA!GR&^T%vvv6>wX#|{HJh2, 3g662W4·Bįh\ٟEwaq_ H%!c#+s9˗<8 5zo, T0\FXDG}₞5 1rK]kSd ׉铸2c}RjPy$#p*'3G2/?dPo}' :p ɷ cd {矟Z"=5 mTO@ J:pCLD_8NYJ׊IHZ G*~?#\g_LNTc$~CS5l P1n ? ʽYg&RbN_(Ὠ "ZLҜbd]LBeQI?t<,*|~CQ<~…/4^Q,jP@Q,߲#CAibg:2NU@Mb!LAt*SI?1chZ\>qbj+NLy2eJVi  "+1b єTH ''e\PY(?Y UXWOLSO%owǿʐTĻσA>:,IŊ&siĨ`^E>^i DU)5Ĩ]8ub.He1(*YeiRVFeeKG|;le.B5HϑPhTKCU TQpx^)fG& g(0<O=6lX=.رCKQH,Rs$AwukEф#ȻKseiVIl=DTҗBiTԔ[G>{_cGo?\׿ƪ^Q!#" so'ԒS7oL)p_G \ueȓTDT$ͅJQ=2R]T(./9gm&`Y1mxu28k6sjHăa w-[i~,+V*VJkr:D?ޤ#ӪN?pnҋ%$+{l|k*z$I#҃d ?`,/&$I^Ղ=aQ-<5xq֭Rھt'i[Fs0L A^υ˩Q׳lD(w@S. ‹cdžC+vnBBW_ y'G䲢lԨۜqSP^_[zz=:~re榼х)H# IVQJժC Mi{Xt⩑#q;D%*Ȋѣ3c1` 8:zj5똿zu3o=n(7@RY}Q}e$eHʾei|fV +Z/jwl=X|})GO.a9‘ ٗ wvƮnɢ8~ɖMZ3v,{mҨ?7fLNٴ) Czf(|z˖s5Vo*NX.ouTwᨻR1pf+m43i,U)ZudιB+87ÝK()Qg:wR@Dw5'C.:<4zuݻ1?m(YA]]=7t,+Hn9\v䑘n]'| AaNrM̋XʕKU9w=ǶߪU>,5ӪiUUˌ|`3bt"̧6l3ڸQ0ĤGRt뎃$]ʇ8Z k5Vme F6#q&-$^_>[JEX}Uj%֯OՄR>2@ꎃw;CWK5sjScw]*2U#N`=XwJRK7yf@-B5S,(Tj[1",K8x {*>VU3PΊQUkÿv(`Ďƚ[ѲR+߽oqȑ+0;/ǾfH-ָ/&[G5:<4 V@խVyUvUp;7B$qZIWTG|&pORA}%j+G׭ʃ#=W5>8 x@)Q==,e,L.?EL88v\@xE鏷q0}ՐB"Y^ wi?+Q~9_9<(1pH5 RAp_Jlx ̐+as 1D9Ѝ7: GZFž+W|tI(=,op~cW==8;gf26k"@׽bie`jصkLf)CN@߃S.[:VG==yMYI{Җ}vCFvYAOOlw*:rBǦc/LWT(ʼ^r-Pwr gF372sHR1kp2iP9]'fʐ؂8#׬ 5Ԅf7TgHg'j#j^5㻪U|{77/K0eIW}V7NZw,_>jȀIO ^Yt<yyӰk^(\3;o^9rU􅺤A^2.'NDK_b !nC\DSq+qd_]⣞%Y$OX;kev`}(6N=˗S9J9!합Fhܺ`9QQNU)4{Ԁdc1u*J(Q (Q@*)#_g#l="5n ;1{>N&Z*kŐJB9'mb unB% 74 K? _󆙵3nY@tL MwM`Y!U!%笳,YZΥQ5'Msqޟafz<Րi:8|[ [N?ǪO^KʹiO]#ci6)n8/QC!Er48PE!ձⵠ\2 "0xKJ )mvJ @{r;,> р:n0*4ܫZm' fH3X,ELz-#"@@|<лlqv рcxN t4+" &n&JI/u @}n/@ͮMUzN87uH0L9NniB4n:X+ 4+$ @@. )V8b XHEz#4)}Dc3_!21*`ؚ챏{ 4\{}t97=6^g'ӕZLηTn/Uq|GƵ)$bɤM\" fQ }xehn'/tHvB:) vHp3& DTd:YR])I& Ah2v@WNtXj<P9VO^/⨞ "־X<, i t @D9xJ HAq44ݎB9FzRuA5 DL4W d+*hP+@)VHEknxns;hv\H4Ⱥy1Gr/PKT3 BB0ʒy)8%|n}y99%ϥ˼U}jO\ږ {=2:25IP~^ҫ5 REZ֭ԆmZ'% w}AnzAKT Yvjʚ4{8f]buYs@GSB܌yT^mt @{,&QzYZ5ɹV6@K߯b!˗:-(5e.A˥c/fZ/8.~!6v#[kH}u]xn4A]BuuXlFjcVx>@k6Z+ZЬE4 DIZPZe`.& Npse'7h}R(DL1 tWC!Ϥ7z9~XrHq3QRx f1 @ƻ!2rv܊+ۀ8{wۮGٸB4nGK1}fǕ>:^ kdK!ͯoqmX:_b{p76նW| H~sAkemGѶG3=ΤXDnMdsnW<-"jU֖;D9~倡4J!7DUzO 0xH; 4Sʄә@\=x)2 @XykapPpGĢn,Cjエr;7Oe=B,ӱsFsͻRek[.EˇW{9",[-!+sښ"B$޹jѺhmbcy>d4=th|/BX^#@c# 3.!ˠf\{%+yx p3];̃2]3iF{]W:k@Gc帆ZpM:W=?;2 k~āߟO55-5@m H)Z||kJz28䵹KwV=ŤcS:qCt NqPl3>7\KӳG'mC:־@@wNGz|hp9@Ǥ9Ԡ hp9 ΁T8y#h aX^ hPy!8vDJ r7ɸ=i7aKn}ڭ ,An:l¾z!ms: `{iOP:VhH9x@ň&J \ b+\aw:Rq9ыZWJs: pYМM.'Ez `o \NhZ鹙MQà0R2VXGyjKf؞dJ[O,p5ĵYٜ,89Vƾo VZκKP\a:_ʃ;t2Rarh.'tzP.KРQ /-hz.|e]a,h"(CTBpMDEA^6hJgF-D{+W_CWʼiXB^zNp&d@ҰtN4(*< .QhPy%Rp  ^׻aU*,=x ])i<:M(ꖞ:ġs5:ӕL EFhPFZ a!2`/ t/ ]WkMs2ŢBW}"yX/sZL${K(K/sǵE%BHU@!tB@!B AA!  aMiFIENDB`mm3d-master/doc/html/olh_images/screencaps/example_simplify_before.png000066400000000000000000000121471324021725400265610ustar00rootroot00000000000000PNG  IHDRHQbKGD pHYs  tIMEg IDATxn8 Leͺ~(<3ͤ۟{|W j;[UShmޫieWT'V6x{Wicb{RfIFW^D37MkFfB6y |42ڔSƫ=,ޫfYxFx+WGk_ۋEFյWz ٟwᑞc3ǃY-O'3K=e;):~fxv`At xdsi@ԍ.D:Rp9ِ!V|^"sX/l?4}i/ܳ8<*/)"1@67 *كK{s^=:Ag(`z'_ope8`**g+پ4WoTx(Nw."Cp6(lx"<=rpIG7AvwQxDyյ UE78ѩuӣ36'F}0ރltgu6C,w+SDlfMፍsBΙcXԆ2V`-#)e߳yt &([<#lL%fyKLqЃl &Xq1 -NCNCx 9jDkB=B!,< n@="ҺWoݜ)3Fx4 hӠdAmfPsv6/|Ղ} "lGY BCkg\ lP|[WR7{ƖhlЖU%zuu5l|g;&+8 }%~%DČg3:/7=/e>"hU^Q9!{8t &۲,g\x[Gnuؾx4cqY9$:gutOIq>zm;6^&Z۷殺yԸ6e&i=Ԛ~jC vQ2yer+:ayxUۉv勖Sg[~l}Ɉ͹̳ԑ #:gt$BNhc;\_M*Sp[,rg*tDb=d{ʺvKg/=*dS'8#Y&FN5u"{63ëԦ5C(AuSg3T3chA鹶Y~,(D?49kwDd'crhʌvуk$#lwDUdHUxZg.$=TD##8ЬINA3k'ZuTl沙5DsNŁzϸlH=MݫVB9T{݈`eᬹ?/Y,͊'\ć.<3H=2j=Rrrj8#Ԭ BtZث#}i@ .m O![8 d:ۗ kDd^M64jpIddMԙΨK(x\[B6l*^BS^~(5c1\A(Z,xv3z4†/:' ( ^Z7AثM_&^Og!m~Ƃ*ؠ38u;lǣ(tZR@|D61FO+RpFk%gWf̯߶nQ]ϵu%۷:H-skw֫vo~ov-u$WG}窖yOHּZW=8|{f֐>ګd%3cyzʲ>ͬ=qPæo[c3]kW#nRͶN7ٌ]]+5"H35٩hDԉPp 6^d#~J0E3W*d3/*sq!KW'[J"),^E%$%{6fFR >OtkT@apMX8{K8p?ﲙhuƇXv{d/B[ZU[a? 6'zgrNޒ}n["96ZtFhezgtv <(b BQlj\#A99+|:H9Nd\W utp!tHsWO$6hZÊhpY#3le9#fVz%eFXkZ}8*0 fCpTAa9ym_ 40h:khwТs$<Ǖi.ĠBR.8|Ez8^RxwC[BtD s\d_p؅\֌Q1l"< gdM6|"AJT8GC*W6ۥd3g.Hc6'U^L\dC6aEnJ́FRƨmY3.-+[9\C3Hݏlh-~Z)+\od-km5wxMQ=`Ps[RZek mbjx5JDԢH/ = Grz I>H庥s9DGⴿa*jyFaP .XnE&|\zޟPtZ_ڃh~D#RRxwśf:p,@#^=/UrߵTo^`2d? jp͵i4TSPgHx9XOA\dC6GDZ.!Ytvp Dbݳh;c#ңxNMUI>f97F).UX'B]Y^ !C4ѹ {hu%D+87MQGWFbKIj~eO*zPId#etCR7'P#7w^<[qz m>l~A\LDg9YN͕x&\Ÿ&O6Uf;Pԯ0E6lsyѸ ϋ%a9-"e>mZ-sF;^ͬe>"ߏ,ٶ ,9hFѡhFѡh4Fh4EFQth4EF(:4-$<R(IENDB`mm3d-master/doc/html/olh_images/screencaps/viewport_ortho_filled.png000066400000000000000000000047501324021725400263020ustar00rootroot00000000000000PNG  IHDR,r|bKGD pHYs  tIME uIDATx=oFSΖBA-S_ѫ7 T[&fX Co,]dS@ZD>(Q_@ ,,@ @, @ ,,@ @, @ , ru9Qb2l6jLŅ|pH%B!,OߖZ-u1 JUUa:>/`!BK S%Z%+Jm GH1NEM<֯i !wOOBUUxziڎ`Ati4>_`i}1D+%XG``!ZFZVat&%Xa&D˶뺓^-`%ˉ+Zv- %X``RWeEK90BPuө MFZDKZh!X9heUԺ=X%XeXDh  h-{ ~}Tj`ARDKzC ƴA 6J"h `w%XxSl0Gy,BL5h FZ Imh hii &I*5֢%Xkq ]^?i*;^7͟A XGr?׾iYJ`E>#Z`Jxh5[}ݦx,G9%tP־#^4*1u]Um$z9//o-h]'EJ5祫n-_ۭnNGdu4y]WSV){6D|rXjEF"L/ӧO4\gn_h:rzg` - !d i =o !k1_SyAM=V Y?qc`eLT#, 𐫇7w!C*c\=9D$ᩛs'2=VhY"(,>M#⚖`?0MTB`*VMCrH?5,Ps}6V, -ȣg|>hYr< ַ4]osp5^i QX}ė/_h;El MC:ͣ'''{LRiZQVG-~5s\\DX%X[Xضumag-h Vzi=htl#VFk`u!%Xku=hXL1ZM6ZmF&S"urV`5 PlzhS9ڴGTp+X%EHoCX,D(aIwP2np77^G .߿o+IF+Xe h!ZhQl hE--*.ZCrЋ(whBqPK[b ha%Xh!Xh!X>C{Kh.h`6Oz∖%Z:ќ`Vr]s`Vy %Z%Zb\KD+q-Nwd`E-{Er* `EKK0,D ,,%\ !{wzz׿pЌ'=Vqъex""XE:ZrH -&Z%Z4FZECDK¢e (XE2w{`- =L'Z͹5'qnǦo }h !,DK,z SLLJD*ߟ?G+Bh>"$@D(bPWA\5, @ ,,@ @, @ ,,@ @, @r8{IENDB`mm3d-master/doc/html/olh_images/screencaps/viewport_ortho_wireframe.png000066400000000000000000000101761324021725400270230ustar00rootroot00000000000000PNG  IHDR,r|bKGD pHYs  tIME:6 IDATxKrݶ@)'*e(/w(mƫތtn4T'4yAߧ/ , a ,@X a@X @X ,a , a?<=:(?xq @5 vCZ JBZi𬀰`A iuBX0.H ZAZ  dD@ZnaMQݨƀa ^+[5bB`H VZs5LTzV7EZ "\#-FkH !-@XKH }+BZlwx+eOj!F$Z[WzU~U*SVg"CZJ<BX0BX0BXDG`H amRq}V i!!f5i*0V56Ry!-ݫE`H amQYw֊CZHkU`lOeبb`{=_(ucwU> =q;K=o I,˲b^_#GEzCOǏ!,nORgRHBPS85R׺Ҋ V.;R DZ i!DتK$|*&B!0VT,m%Z !0Me]}vws iu2ȹ.$iR'BX݄eYC^__U>ek)DZCZCb'AҋiWu2LiHM_)$!Vm`($F틪R#b $v~_aAP9}Cn#~)gTBhQZ.9e;w*ڧb~i*{Z#DS"g8k"$~q/jI_QO+%^N:}a||(#Vi _l\9OYf=M K%ԲO9&vnLpsrt(=\AZhQ"8߃CV GX+MN 50FVTlԎx BZٕI IzBaM҇իJfK;KU[B3R kQBѠH(u?߿ex?N!OB`RcrIVuDV0(aaҾ뤑bigu4=Zɑ)"rGFQ k9zif|/-L%tkBiR42+-ol-hr]fd`}`CK.P]3ߣ98R"}VEXEɗS!?o+Y'i-J7jDRʊk%[^^iIӱSeʕjSa*YshN.y_a1yjl7 ͅqI#KQ>-9erZR_a-*rFֳ#^,iϱz^:;n␃l\~dg cuJ; ž 8ZJ"/}l](RVS[^J$I "-"G>^iW(=d`UV)0+YJYɉ4Xݳ`j2+BXJ8r#thL3-ظί->DX#]kP-'?x=̌Ke^4}%c iu.Y. }i6NoR؜eQ9e,i޳dBZFf,Yu+-|4kcew$ceUl{j_i_8k4o[b~;߿6҆ +V:UҰqj(YȉZQh"T>a9cD4"YFٚY$eY~F掊|;m$R ɪr==vZT>_JzO9,oߎüj >R%G!ͤK"=uS[[j;V{[F_5z;,~vii!!U㐃==D?vjBXjYlq23ne"s'")Yj҇-K;kJּ_hQks;7sJ]="* $4.V]w`K"B7dUx3]ZDX裕 Z}FcOo+ȣa(a-&+pJ"%ir癕ϺLKׇrBZ\X%vݜ봍˓dm=}k%iчUاz\'s̾i ڴr +I at@*ZcJKC{E=}wrȨd0~3#}Kg&mчHVbK9z}y9jҲiDXDZSGLVPZ>:r9VE0r_bU/fI?{0U&)^(qZ* EfFDZ9r)Y˴w7)!(=Yk5z}3ڷ`y 9DX#H׌TRPYtِvê֠Y52Ci<LsշAXHFVT)&-]Nd\kϩ%LzY&"IU~Oh!BN]H.CiKdC>kчՠ˪ w[R9S#gugޥ&Z|(jkiw>vZTVtV0J1^җ]603IivNzZi4-9EWt}/Z}peWhBXN[y_nHq^ey#5f2)b)(}",ݻ=p4z3őX"MS-"|8j箋GruNlI$$id=x yu-!ɄL I"ғgz jPKsb26UIZ"I(6u,^ޯUZ~XK$!6ĜFuAdLҺFFA5ӽ_?_5~3pIVHTѥ+>9v?ɶ=f>W)85EZ9K%dwSj+CXEv hMnZkh8D>)Sh%;=XH  i dpF}aM%dJ>繇TeRB>vT곲NUgIH ȧT)F$[.tL.am'HJdW4Uy"-WB HEӣBZ[C ,!F(75_(JsɊքYVC\ im,du-^IZR#+RD#BX@W6gLwBZ6yC5ܣxb +`JBZ \9XkJ{NH a!##¢#+‚*}ƃ‚AVBXH4p'}'K ,K] +`J‚)*=BZ  -*ᅰY!-CWzdLQUGʍ"Zܕ>$ rBX ' aNB‚AVHh=a6=?4C` X` X X`` X` X X`{۷_~_ M/_LY' *Δ%X`zB(S ʔ%X*=>>,jLY@8!Xᙲ BLY@`!P,K@(S)K(,qb\MY%T@K(VLY`)KeӽWv:͇ e4z6M q ZԆisY\.Po>|0e ~ؿ4ϓ)+V,0u}Yz͎SSh,BB~rɎW&S`SSl:O/֖s5^X+,;Xέu:J]^`6+V^ӆΔ%Xtj*) Xtj*%S/nvP,w[[ *(5!Oi99Ѳe7h7|n,Jݯ, NX&LI%#w ;y,XXέmJJyv֧ϵ/2aڃ,*LM߬KOZݯu/VRUq& =枴jVp)+uOYއb44mQ Vlb%XUDkBn?+6J f :1m=ZS8RSr^k֩)ֿBL o](rh+{jJyܺܫp)қp7e jԳ1Su`4wbZXsT+X,*:5Դr½[`'*N %,Iw?ؔPJ/9ZKE)k֒ʙBqsڢDL^ց4u@ՌϜZb;!џ+wzq/{+{JOX%NDK9& ߧ{=%s:Jj/ KK)eb}6kL[% A5{[SU"Z4߄+vښ#ZNF$L؄PM]X֭݊+)]hCS(یع%Za?F!=$ViW&DB&~Bw+XMX%++gNZC1BDkjzRhދ.ƪGǞkpR2S`*-ƽ:ۍO2Ãhsش5וD/gJ IL[ۿ0Е眠 1_MR+~baMXӖt=!XA O8KC- Aj镇 T3%9ҒEˑsВ0zh,S{}Q9%X{ SD\v|pEߤ%XӖiӮ5t:N&{X=^z坥`!Zŗ9)VWzi#tĒ-En;!YEkafQ7*~lgݩ^H\1q, d)Kx Vo=ba}ma M~x5U+J, }L}>{XG۸,4Ēr, ^;^`AIk*F9ʲPҴ5QbWxYέXg9/XI_QršQN[BcST`RN PfԞ =#VKZ1aŦ&W  yKm9)XPqsLj5s1aE#w3WC>=?x*`m/+3G\RD{X+, @6lׯ_ׯ=(Xҏ?DK-:+-߾mh5z#qǏͻ=; &]eDĄe¤` %Xh8{Xj^iL]l*Z-.DD B ղAhٌ7aa2i!X…h %Z==ek]Ჯee` %Xh`!\E( W2ѲoԵh DD >{X;W>Wh2aa2i!X…h %Z5{XWi~}-`rPm 6L` X` X X`` X` X X`` X`y,@ @, @ ,,@ @7-_2ZIENDB`mm3d-master/doc/html/olh_images/screencaps/viewport_persp_wireframe.png000066400000000000000000000104761324021725400270240ustar00rootroot00000000000000PNG  IHDR,r|bKGD pHYs  tIME'k:IDATxM~6GȧeKֲ}º=4=B63I(YA`)a , a ,@X a@X @X얿9p^/qsB %{@X*w,) al"'<$~'e!,9E)v]ޑf EBXHPDBXBX@yDL/w,@X@zr8' ڹ) a a"e¢8KqBVHY@b OK %Ek>u:Ax07al %O[=v_j7e" bNK-54^>GJƱsR5|qj3J+hV6z-֋HX/v`~5IϤի6bD)H aM$$efaxX/(iR*5{J"}]o7y4'WΆS&/i˯ᨥ_F:X[Zz![&QYgŬ aHX=njojqFFJoH4q5!SFb #c.a2N88{Uf%I$!C2)հ HX.(-*-߬K(->RRv,sê/ Te9. TZʋ-,=C>%!yci+:_>&eͭ6iiod+FRQ##Hkdڒ.bIK->_LZo:!,Vͺz ek3'I}EX8{ίCX'N[ҥKZd2jQ@Kc{ @,8-iJZ ]I5EXe E|Pe*Èǔ6ɏMzďr+c0+'VN\M+-謏,,z2!~#~R( 㽛}ZJxryߖ--庤t- `iK\r&x`龸eWX䶢&osL$gBд9Y;@G%:Kbi)Fk!?yWiz|ۚz%:ynuv3/M|= f4!VS|'aGjp\C?)?/uj\:ڝ%ҒHXMiKFZzT)?K,wjqMt aX\44]QϹd[KK2#|ϵ>AXSڗGJ vIW!-iy:R2mw9IOJmÒ?}y,=KeeҠJ jeYX*kikTteYϗ==o-e0!z%rPR|skz/?ߖ_i}\iNUn%rj .ir&}_څeHr*ky-y )Qj-^j_JÖt_n=7[KD[]sJK3ߤn&c֯ʮj+"[@*J㤛zZRH a3mPZ8L/ڕ"Fa5KdM)MS{O$,{HAcuke ů߷\CIcsA7RAO a!S Z i!—|[XGZЄ=Y,BXW4 qeZ_CgdqΙtN~|~ q8 y˪yDDXbZS:H aZ\vYmuސB^K--aa9s3(F a.q=uid5y`‚fg.= ,# {576[5Yuo}-(q64{$i!,k^Q9BX Wϔ:s=U6`bja:@נ& D= ,hT]詊aZġtl\ % -ӊk i!,\\> WI^q2 I$A\ʊA#7?h@n^曶EJ>",$YS^=BXpB!^^IPd+\%a , a ,@X a@X @X ,a ,@X@X @X ,a ,:[Ԁ=IENDB`mm3d-master/doc/html/olh_images/tools/000077500000000000000000000000001324021725400201675ustar00rootroot00000000000000mm3d-master/doc/html/olh_images/tools/Makefile.am000066400000000000000000000020401324021725400222170ustar00rootroot00000000000000EXTRA_DIST = \ atrfartool.jpg \ atrfartool.png \ atrneartool.jpg \ atrneartool.png \ bgmovetool.jpg \ bgmovetool.png \ bgscaletool.jpg \ bgscaletool.png \ cubetool.jpg \ cubetool.png \ cylindertool.jpg \ cylindertool.png \ dragvertextool.jpg \ dragvertextool.png \ ellipsetool.jpg \ ellipsetool.png \ extrudetool.jpg \ extrudetool.png \ image.png \ jointtool.jpg \ jointtool.png \ movetool.jpg \ movetool.png \ polytool.jpg \ polytool.png \ pointtool.jpg \ pointtool.png \ projtool.jpg \ projtool.png \ rectangletool.jpg \ rectangletool.png \ rotatetool.jpg \ rotatetool.png \ scaletool.jpg \ scaletool.png \ selectbonetool.jpg \ selectbonetool.png \ selectconnectedtool.jpg \ selectconnectedtool.png \ selectfacetool.jpg \ selectfacetool.png \ selectgrouptool.jpg \ selectgrouptool.png \ selectpointtool.jpg \ selectpointtool.png \ selectprojtool.jpg \ selectprojtool.png \ selectvertextool.jpg \ selectvertextool.png \ sheartool.jpg \ sheartool.png \ torustool.jpg \ torustool.png \ vertextool.png mm3d-master/doc/html/olh_images/tools/atrfartool.jpg000066400000000000000000000010261324021725400230450ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"&!12AQa1!A2a ?fIXq !#HD](~r*"0S]3 .G vFʙ_a44X`54Mɨk"gj2͸PeJ5ӥs:v!t(p-WlL˺ґpH\D&毽hnt H"\nomǺRHjܒRmm3d-master/doc/html/olh_images/tools/atrfartool.png000066400000000000000000000040441324021725400230540ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME 8}qIDATxYHH IENDB`mm3d-master/doc/html/olh_images/tools/atrneartool.jpg000066400000000000000000000010501324021725400232170ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"'A1!"Q#2B!1a"A ?DlڍOL=PU9Q>>k,mcXwO>\o$m$ 31y$ԟi|A:K׍Pؤm[vŽM%݋r^YW \AH"I+)JA4.d&uv[Y8[)9;$]X)9kmr4q]#"cUU RuWU[;vRmm3d-master/doc/html/olh_images/tools/atrneartool.png000066400000000000000000000040441324021725400232310ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME ' RIDATxYJ6\>IENDB`mm3d-master/doc/html/olh_images/tools/bgmovetool.jpg000066400000000000000000000012131324021725400230430ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222")!1"AQaq"1A!"a ?wEꚦUMA4٠JIsd@xu:% {Ң:#H$Un1eE8:F݊'cȈ 5s1'[j}3UHEg(\3 Ǒ?Wv0=@Lu<Ϗʺ%mEJ)I n>tԆf OD'j,ȡ_{@=P̃K*ihFI܃,WX٠47K\PABUX}馚,؊ mm3d-master/doc/html/olh_images/tools/bgmovetool.png000066400000000000000000000005741324021725400230600ustar00rootroot00000000000000PNG  IHDR$xbKGD X pHYsHHFk>IDATHՕ1 0_D(m tqZcs2zt!xnM-jĨߒ/?^QU#dF\.ahadFѭaX1vnun|)cր(D&'cy~8<JIKp DkoApo6ϲ8-cuS nZeXKB!crs9oJ?IENDB`mm3d-master/doc/html/olh_images/tools/bgscaletool.jpg000066400000000000000000000011501324021725400231640ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222",!1"3AaQS"Aq!1Qa ?8K˩sח7D8`\TlVp am{w q/2ݸ( ۙw;qu`F /yJw4ȫͰ@<´}f?T3Ԅ Ď.|A1~FQI۬LQ3 b| Oi]^́]{*xjQzhAEryoz^Ne# +ʑ;wڡ7c?ʔ_˓#gnyLYZA<݂[/ʡ+(H{_RL 3kTW03mm3d-master/doc/html/olh_images/tools/bgscaletool.png000066400000000000000000000004751324021725400232010ustar00rootroot00000000000000PNG  IHDR$xbKGD X pHYsHHFk>IDATH헽 0d67Wǀ/rO!\ENWKK116o0 1$gRPJ) "":Zsn W.xfihw晨# !""aӗ¶(armp,ey:)Ʊ,-Wři@!l{u  ;>iADD\FBZ=krBK2PIENDB`mm3d-master/doc/html/olh_images/tools/cubetool.jpg000066400000000000000000000011731324021725400225070ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"+!1"Aa#2BRT!Q1 ?cpD.öӰ et*;OׄV{/B-v I+@P{]OڡDѨlҎ4LxQw2&3ګIRF/b ɒ0:VAr͐1)6$,@ֆə[,ⵊA`p Q ysMTϾlC":AF 4T2q>T{w կbJ\J)qPhFOMf`b%[ lV*@!Fd,gld$ I=I%PU.{__mm3d-master/doc/html/olh_images/tools/cubetool.png000066400000000000000000000040441324021725400225130ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME &RIDATxY~~ ttEECCttssrrttrrss%Q+&IENDB`mm3d-master/doc/html/olh_images/tools/cylindertool.jpg000066400000000000000000000010701324021725400233760ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"01!Q"2BSUVacq !1AQq ?bH\xp_hJKJm8NjMjl{(NFΙ(ŷi uM>AÞ%ì:!M<t<7zJҴhn.<72m_caqqE[(壬wXG[O*9x\F$a|x}}_:?`:?TkJo݁2CVD X0r)i *R9I9kmm3d-master/doc/html/olh_images/tools/cylindertool.png000066400000000000000000000040441324021725400234060ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME :LIDATxYIENDB`mm3d-master/doc/html/olh_images/tools/dragvertextool.jpg000066400000000000000000000011651324021725400237450ustar00rootroot00000000000000JFIFHHExifMM*C  !"$"$C"*1!$2Aa"BQr!!"12Q ?ɴW3lk,nwFEtC3GQ-N&mRG"fh9üf1.8< m5dڿTᦐry  / G^FO`qpW^ûQtͺF[ډecE$]5 n0fS k-j#}ElvsI$g$y d<7m1;z4EA#4,7=dvI%I$xPrW$nVmm3d-master/doc/html/olh_images/tools/ellipsetool.png000066400000000000000000000040441324021725400232320ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME sIDATxY-hSIENDB`mm3d-master/doc/html/olh_images/tools/extrudetool.jpg000066400000000000000000000013021324021725400232430ustar00rootroot00000000000000JFIFHHExifMM*C  !"$"$C"4!"12$367AQRTqsuv&!1"AQa ?9 6y-Xk`=wbr2#κHsIflv ƞ,^,@|<^_HG׹~w}҂_?_7/BְUmml` N Ϯ`ֵ,ZøW8VkJ傒z # V9ui{kzi翽Si!'&NRuQ7m5 JkO , ~u*_0O@N1~y3gM4)ɡZoNRz m+nV.\QիZz(J4{9€@Pi!(O:];tu*1 Cmm3d-master/doc/html/olh_images/tools/extrudetool.png000066400000000000000000000005021324021725400232500ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  tIME ngSIDAT8O @[a0&}(()wɽlZ0ec)Eq, "GYDRCgR8@DNeg<\*PaMΥsfs@0j:P/3kW>ߋ<gc(锷uYėc(iw?å#be2~υ<#!0 RǤ#{|0IENDB`mm3d-master/doc/html/olh_images/tools/image.png000066400000000000000000000004321324021725400217560ustar00rootroot00000000000000PNG  IHDRKlbKGDC pHYs  ~tIME%{]IDATxՓ DUag"==*@Hd|OdONc@oIENDB`mm3d-master/doc/html/olh_images/tools/jointtool.jpg000066400000000000000000000007761324021725400227240ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"$1!2"BA!!a1q ?g[][)Si\g13G4c Ɍa)JG`䓓F Z5'!uSZ:'i3 >MksZ!.˝,%(m&ӥ7>8߅-z~b[U/YBQ?c3SkSlzhJQlKčۤ;2>=C*L׭tH1Hcmm3d-master/doc/html/olh_images/tools/jointtool.png000066400000000000000000000040441324021725400227200ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME 7!'rIDATxYi&C7nIENDB`mm3d-master/doc/html/olh_images/tools/movetool.jpg000066400000000000000000000010321324021725400225310ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"%!1"#BaQ ?H[`<3a93pr([p6Ic}vHܣ eaH:$h"[zY㞼ܷ#$RܘR>v6u@Qoi(Q2OӍ[rVC24m9a6WBN6 ČcIUNSE[Q=)WT,řY1$ĒI$N1Humm3d-master/doc/html/olh_images/tools/polytool.png000066400000000000000000000003521324021725400225560ustar00rootroot00000000000000PNG  IHDRĴl;bKGDC pHYs  tIME RwIDAT8; P'Hg#HO$׉K`)C:5ZW5>0YMWuy8[֐*I LFb9AIDATxY"XIENDB`mm3d-master/doc/html/olh_images/tools/rotatetool.jpg000066400000000000000000000010221324021725400230600ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"%!1AQ ?fs=7[ Ic$>Ok3b@p뗔LeEUh{*MhG`7ì댚)HʆcZVo?@2)A})Amm3d-master/doc/html/olh_images/tools/rotatetool.png000066400000000000000000000040441324021725400230730ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME \aIDATxY cIENDB`mm3d-master/doc/html/olh_images/tools/scaletool.jpg000066400000000000000000000010231324021725400226520ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"/1!"6ARUaqu ?jO'ҿO\m. */&[ò@7-Ͷ!tjkךߎ۬^(Pq&<9D%D8J!mνcwxuFsfyW_+0^APJ3`'ɧ&Yu@-.ER^S>U(*~dyՁ`BV n9 '”mm3d-master/doc/html/olh_images/tools/scaletool.png000066400000000000000000000040441324021725400226640ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME nIDATxYQQQQQQ   CXIENDB`mm3d-master/doc/html/olh_images/tools/selectbonetool.jpg000066400000000000000000000011441324021725400237120ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"#!1"Q2 !1A ?8O*-O:ͤz!+@A͖@ZkL|B!`To]Sll1(#ɼZKr(b>5$ YfWo ? +O92rVOII5GMT5~sJ.ku T]S~Yו!hb/Lc蜿˝e=d_^kj XsJHS YvD HiPb#`E^qXa .6M׮I4롺Zht \ nBU.|Y;#|4EV ̜)m?y PJo~$ "Pxp`kn =sd-a~#xm֕?޶ֲ,aWV m GziflqpcW7J+-SVtx `DNM4ԶHKp(5R̘mm3d-master/doc/html/olh_images/tools/selectgrouptool.png000066400000000000000000000040441324021725400241310ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME '<IDATxYa9eIENDB`mm3d-master/doc/html/olh_images/tools/selectpointtool.jpg000066400000000000000000000011131324021725400241140ustar00rootroot00000000000000JFIFHHExifMM*C  !"$"$C"#!"1A%!"1Aaq ?89B ~6|Fd^ӳq˖6?|82G%qIY"fJH$)"Qm1ydmщ4./Hqsf/ #Q~Ca9aVsDT)aRm67#*&4q^(؈b3iU~$z~9ju*(8oO<)wJhh4UXҲ>:ބ96 F /wR|oƶԸIENDB`mm3d-master/doc/html/olh_images/tools/selectprojtool.jpg000066400000000000000000000014471324021725400237470ustar00rootroot00000000000000JFIFHHExifMM*C  !"$"$C"+"!1#B23A&!1AQaq ?:i;c߶'hmPZ ZN\?mlJuF.ע4Ltm(EZąy LEQTєNd֏r~z̷\ٺ.x~8S@O50ԗ]QeRxJHFd*-U}WΪdČ-}ٱ:%զy+JIՀBά lBo6 mЬG)0:x8B`EԲ?;rOoM$0Ć&|?.FWr/أI M)I7Dž Y @4/(]b{ϣQNql$fHhhEonizFe1NjlO}1$lc`#s/MmZʽA xBF$JHjao)Jəip?GϚRmm3d-master/doc/html/olh_images/tools/selectvertextool.png000066400000000000000000000040441324021725400243120ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME 0CIDATxYMZ>IENDB`mm3d-master/doc/html/olh_images/tools/sheartool.jpg000066400000000000000000000011011324021725400226620ustar00rootroot00000000000000JFIFC    $.' ",#(7),01444'9=82<.342C  2!!22222222222222222222222222222222222222222222222222"*1!"24AQau ?{)lMGڔ nh9'SzINay2:`"A-xN4ړ,;>y+w]?ʡ r>Z(i>i X{$O UoW\n'MZeNh#he\;}s]6Vo'#s类ݏxh)˘Ò^})vkR{) pTFp5mRz \{je1 ;qSN! H8Mx*]cn 2qq4Amm3d-master/doc/html/olh_images/tools/sheartool.png000066400000000000000000000040441324021725400226770ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  ~tIME Z IDATxYQQQQQQRIENDB`mm3d-master/doc/html/olh_images/tools/torustool.jpg000066400000000000000000000014061324021725400227440ustar00rootroot00000000000000JFIFHHExifMM*C  !"$"$C"'!"2$AQ"!A"1 ?P˗ǦjH8jIHz0vfִqKJ, 0"Z]!YY~_s+#3"OwvB<-WdZ%hJ 6K^GVYFF!8n389NOzٺyfQ#NxV uG̍G>9;Fʩ[k}|cF~ um{{OoYf_S'?zqR㨵{.XOnibXI%F;KR;ffbӫ& #z͝+_mm3d-master/doc/html/olh_images/tools/torustool.png000066400000000000000000000004121324021725400227440ustar00rootroot00000000000000PNG  IHDRĴl;bKGD pHYs  tIME &@4IDAT8U1 K8e:A=2*Ĉ! 6pxKB)p,]Uz4]f8~Y3)7ށ΁vY%)m5$uv$Iݹ鵌A/TՉ& *&o:ME#M(zr-Contents


Overview

Help! What should I read first!?

Here is a short list of the most useful documentation.

  • The Quick Tips page contains a list of things that every regular user should be aware of. If you are impatient and only want to read one document, Quick Tips is the one to read.
  • The Main Window documentation gives you an overview of the user interface and a high-level description of the program's features.
  • See the 3D Model Introduction for information on specific topics.
  • The Tutorial is not yet written. When it is done it will walk you through real-world usage examples for all the essential modeling features.
  • Everything else is reference material for specific topics.

Misfit Model 3D Introduction

Misfit Model 3D is an application that allows users to create and modify triangle-based models. It currently supports a variety of 3D vertex manipulation tools as well as texturing and animations. There is a plugin system so that extensions can be written to provide more tools, commands, or model import and export filters.

Currently Misfit Model 3D has its own file format, but can also export models in the Quake MD2 and MD3, Cal 3D, Milkshape 3D, COB, DXF, and OBJ file formats.

When you start Misfit Model 3D you will see the Main Window. The Main Window has a set of viewports that act as a canvas for model manipulation and a tool bar that provides interactive model manipulation features. There can be multiple Main Windows, one for each model that is open.

See the Main Window documentation to get an overview of Misfit Model 3D's user interface as well as links to more specific feature information.

mm3d-master/doc/html/olh_index.page000066400000000000000000000000601324021725400175230ustar00rootroot00000000000000PAGE_TITLE=Contents PAGE_CONTENT=Influences Menu

Assign Selected to Joint

Overview

Assign Selected to Joint assigns the currently selected vertices and points to the currently selected bone joint. You may have more than one bone joint selected.

Select a bone joint, chose any vertex selection tool, and then use Shift-Select to select vertices without unselecting the bone joint.

Keyboard shortcuts

  • None

Auto-Assign Selected

Overview

Auto-Assign Selected assigns the currently selected vertices and points to the joints that MM3D thinks are most appropriate. You can increase and decrease the tendency to assign a vertex to multiple joints.

Generally auto-assign works fine when the bone joints are obvious, requires some adjustment in weight when near a joint, and doesn't do a very good job at all if the vertex is betwen several joints but not along one of the bone lines. The algorithm is not perfect, but is a good starting point to begin fine-tuning manually.

Keyboard shortcuts

  • None

Remove All Influences from Selected

Overview

Remove All Influences from Selected will unassign any bone joints that are assigned to the selected vertices or points.

Keyboard shortcuts

  • None

Remove Selected Joint from Influencing

Overview

Remove Selected Joint from Influencing will remove the selected bone joint as an influence from any vertex or point.

Keyboard shortcuts

  • None

Convert Multiple Influences to Single

Overview

Convert Multiple Influences to Single will find vertices and points with multiple influences and remove all the influences except for the strongest influence.

Keyboard shortcuts

  • None

Select Joint Influences

Overview

Select Joint Influences will select any bone joints that are assigned as influences to any of the selected vertices or points.

Keyboard shortcuts

  • None

Select Influenced Vertices

Overview

Select Influenced Vertices will select any vertices that are influenced by the selected bone joint.

Keyboard shortcuts

  • None

Select Influenced Points

Overview

Select Influenced Points will select any points that are influenced by the selected bone joint.

Keyboard shortcuts

  • None

Select Unassigned Vertices

Overview

Select Unassigned Vertices will select any vertices that are not influenced any bone joints.

Keyboard shortcuts

  • None

Select Unassigned Points

Overview

Select Unassigned Points will select any points that are not influenced any bone joints.

Keyboard shortcuts

  • None
mm3d-master/doc/html/olh_influences.page000066400000000000000000000000741324021725400205540ustar00rootroot00000000000000PAGE_TITLE=Influences Menu PAGE_CONTENT=Bone Joint Details

Overview

A bone joint is is an object that forms one part of a model's skeletal structure. The root bone joint has no parent joint, all other joints have one parent. A parent joint may have multiple children.

Vertices and points may be attached to bone joints to control their movements during skeletal animations. When a vertex or point's movement is controlled by a bone joint, the bone joint is said to be an "influence". Vertices and points may have up to four influences.

Creating a Bone Joint

Use the Create Bone Joint tool to create a bone joint. If there are no other joints in the model, the new joint will be the root joint. If there are other bone joints in the model, the bone joint nearest to the point where you created the new joint (in 2D space) will be the new joint's parent.

At this time it is not possible to change a bone joint's parent or to insert a bone joint between two existing bone joints.

Other Bone Joint Details

To assign a bone joint as an influence for a vertex (or point), first select the point. Then you can use the Influence Properties panel or Joint Window to select the bone joint for that vertex. You can also use Shift-Select to select a bone joint in addition to the vertex and then use the "Influences | Assign Selected to Joint" command.

If you have more than one bone joint influence on a vertex, you can control how much influence each joint has by changing the weight of that joint in the properties panel. Weights range from 0 to 100. The sum of all influnece weights does not have to equal 100. There are three types of weights:

  • Automatic - The amount of the influnce is determined by the position of the vertex relative to each of the vertex's influences.
  • Custom - The user specifies the amount of the influence by entering the amount directly.
  • Remainder - The amount of influence is the sum of all other weights subtracted from 100 (or zero if the result would be negative).

See Also

mm3d-master/doc/html/olh_jointdetails.page000066400000000000000000000001011324021725400211010ustar00rootroot00000000000000PAGE_TITLE=Bone Joint Details PAGE_CONTENT=Joints Window

The Joints Window can be opened by selecting Edit Joints... from the Influences menu. The Joints Window allows you to rename bone joints and assign vertices to bone joints. To create bone joints, see the Create Bone Joint tool.

Joints List

The joints combo box lists all the bone joints in the model. Selecting a joint in the combo box will cause that joint to be selected (all other joints will be unselected). After selecting a joint you can rename it, delete it, or assign vertices to it.

Rename

The Rename button allows you to rename a bone joint. Bone joint names do not have to be unique (unless you are exporting to Milkshape 3D format).

Delete

The Delete button deletes a bone joint. The parent joint of the selected joint will become the parent of all the selected joint's child joints. You cannot delete the root joint unless it is the only joint.

Select Joint Vertices

The Select Joint Vertices button selects all the vertices that are assigned to the selected bone joint. All other vertices are unselected.

Select Unassigned Vertices

The Select Unassigned Vertices button selects all the vertices that are not assigned to any bone joint. All assigned vertices are unselected.

Assign Vertcies to Joint

The Assign Vertices to Joint button assigns all the selected vertices to the selected bone joint. Selected vertices that were assigned to another joint will now only be assigned to the new one (when using the Joints Window a vertex may be assigned to only one bone joint, see the Influences Properties Panel if you want to assign a vertex to multiple bone joints). Unselected vertices assigned to the current joint will still be assigned to the current joint.

Press Ok to keep your changes or press Cancel to ignore any changes.

See Also

mm3d-master/doc/html/olh_jointwin.page000066400000000000000000000000701324021725400202560ustar00rootroot00000000000000PAGE_TITLE=Joints Window PAGE_CONTENT= GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. <one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. <signature of Ty Coon> 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. mm3d-master/doc/html/olh_license.page000066400000000000000000000001041324021725400200350ustar00rootroot00000000000000PAGE_TITLE=GNU General Public License PAGE_CONTENT=Main Window

Contents

Overview

The Main Window is where you modify a model. The Main Window has a menu bar, a tool bar, a status bar, and a number of viewports that let you see the model from various directions. There are also several dockable windows. The Properties Panel in particular can be very useful.

There are two modes for the main window. The default one is the Model Edit Mode. This is the mode you are in when you start Misfit Model 3D and are viewing a model. In this mode changes you make affect the position of polygons and bone joints. The other mode is Animation Mode. This mode is active when you have the Animation Panel open. In this mode changes you make affect the current animation frame.

Tool Bar

The Tool Bar has a set of tool buttons. The tools allow you to manipulate a model interactively. For example, you can select the "Draw Cube" tool and then click and drag the mouse in a viewport to create a cube. Each of the tools in the toolbar is also available in the Main Window's Tools menu.

Menu Bar

The menu bar has several menus that provide other functions to modify or create a model.

The File menu allows you to open and save models. There is also an export option to allow you to save in experimental formats. If the file format you want to save as does not appear in the "Save As" dialog, try the Export function. The most recent files you have opened or saved are listed in the "Recent Models" menu. You can load one of these models by selecting the filename from that menu. Additionally, the File menu also allows you to view available plugins.

The View menu allows you to change the number and layout of the viewports in the view window (you may have 1, 2, 4, 6, or 9 viewports). You can force the viewports to show the whole model or selected region by selecing either the Frame All or Frame Selected options, respectively. You can select how to display the model in the othographic (canvas) and perspective viewports based on four options.

  • Wireframe - Shows the model as an outline of all faces.
  • Flat - Shows the model as a set of flat polygons (with lighting).
  • Smooth - Shows the model as a set of smoothed polygons (vertex normals are averaged between all polygons that share them; with lighting).
  • Texture - Shows the model as a set of smoothed, lit polygons with textures applied.
  • Alpha Blend - Shows the model as a set of smoothed, lit polygons with alpha-blended (transparent) textures applied.

There are also some rendering options in the Render Options View submenu. These options include how bone joints are displayed, whether or not texture projections objects are visible, how missing textures are rendered, whether polygon edges (3d lines) are displayed in the perspective views, and whether or not back-facing polygons are drawn.

You can choose how you want bone joints to be displayed. Bones draw a diamond-like object that is thicker toward the parent joint and thinner near the child joint. The Lines option just draws one line between each parent and child joint. The hidden option disables drawing of bone joints.

The Error Texture options indicate how you want unloadable textures to be displayed. The Red Error Texture is a black 'X' on a red background. It is designed to be an obvious indication that textures are missing. If you do not care about missing textures you can use the Blank Error Texture which will render missing textures as if the mesh had no texture applied (material lighting properties will still apply).

The Render/Hide 3D Lines option is used to enable/disable drawing of lines in the perspective viewports. This can be useful if you want to see selected edges in the perspective viewport.

The Draw/Hide back-facing triangles option is used to enable/disable drawing of triangles that are facing away from the viewport camera. By default these are rendered as darkened polygons. In some cases you may want to these polygons to be invisible if they are not facing the camera (such as when using transparent textures).

The Tools menu lists all the available tools. The options in this menu are also listed in the toolbar.

The Model menu has features that affect the model as a whole or large portions of the geometry. It also includes the Undo and Redo options.

Edit Model Meta Data allows you to attach user-defined text values to the model as key/value pairs. In general these have no influence on the model or its geometry, the are just a place for you to store arbitrary information (such as author/artist information, copyright, URLs, etc.).

Transform Model allows you to apply a transformation Matrix to the model. It opens a tab window with different types of transformations. There are tabs for translation, rotation, and scaling, as well as a tab for a user-defined matrix. In some cases the Matrix you want to apply may not be undo-able. If this is the case, the program will warn you before performing the transformation. See the Transform Model Window for more details.

Boolean Operation allows you to combine two object into one. See the Boolean Operation Window for more details.

Set Background Image adds a background image to one or more of the six pre-defined orthographic projections. Background images can be useful as a modeling reference when attempting to create complex shapes. See the modeling tutorial for more information.

Merge imports the geometry, materials, and animations from another model file into the current model. See the Merge Window documentation for details.

Import Animations imports the animations from another model file into the current model. The skeletons of the two models must match.

The Geometry menu lists non-interactive operations that modify model geometry.

The Materials menu lists non-interactive operations that modify groups and materials. See Material Details for more information.

The Influences menu includes functionality for dealing with bone joints and how they influence the model geometry. See the Influences Menu and Bone Joint Details for more information.

The Animations menu provides functions to manipulate model animations. There are interactive and non-interactive functions provided by this menu. See the Animation Panel and Animation Details for more information.

The Help menu brings you to this documentation.

Status Bar

The status bar contains text (on the left side) that describes the results of recent operations on the model. On the right side it shows you how many vertices, faces, groups, bone joints, points, and materials exist in the current model. If you have any vertices, faces, bone joints, or points selected the count will be shown with the selected separated from the total with a slash ('/').

Viewports

The Viewports in the center of the Main Window are where you view and modify a model. There are two types of viewport views: Perspective Views and Orthographic Views. In this documentation orthographic views are sometimes called canvas views because those are the views in which you can use tools to change the model (like a drawing canvas in a 2D paint program). The view type and direction is indicated in a combo box above the viewport on the left. The field of view is indicated in a text entry box above the viewport to the right of the view direction. Larger numbers mean you can see more of the model canvas (think of the opposite of zoom). Three short colored lines indicate the origin. Each color extends in the positive direction along an axis. The red line extends along the X axis, the green line extends along the Y axis, and the blue line extends along the Z axis.

Ortho Wireframe

Ortho wireframe

Ortho Filled

Ortho filled

Persp Wireframe

Persp wireframe

Persp Filled

Persp filled

You can scroll the active viewport by clicking on the arrows in the upper-right corner. The four-way arrow allows you to click and drag the viewport. You can also use the middle mouse button to drag the viewport. You can zoom in and out by using the magnifying glass buttons above the viewport scroll buttons.

Holding the Ctrl key and clicking on the pan arrows in the corner will rotate the viewport. Holding Ctrl and using the mouse scroll wheel will also rotate the viewport.

The view type and direction can be changed to see the model from various angles. In the Perspective View near portions of the model appear larger, far portions of the model appear smaller. The Perspective View may also have visible lighting and texture effects. This view only allows you to view the model. You cannot modify the model from a viewport in Perspective mode.

By left-clicking and dragging your mouse pointer you can rotate the perspective view along the horizontal axis or vertical axis. By middle-clicking and dragging you can pan the viewport left, right, up, and down. Using the scroll wheel will zoom in or out. The right mouse button has no effect in the Perspective View.

The Orthographic Views show the model from one of six directions: Front, Back, Left, Right, Top, or Bottom. These views are a CAD-like projection of the model from the specified direction. These views are not modified by perspective. Two cubes of equal size will always appear the same size in this view regardless of how "far" they are from the viewing plane. Each of the six orthographic views is a canvas view, where you can create and manipulate model vertices and faces. The othrographic viewports may also render the model as a wireframe, solid-flat polygons, solid-smooth polygons, or textured polygons.

An orthographic viewport can be rotated by holding the Ctrl button and click-dragging with the left mouse button. You can toggle a viewport between orthographic and perspective by pressing the Left Quote (Backtick) key.

If you want to be able to save your current viewport settings (pan, zoom, and rotation) and restore the settings at a later time, you can press Ctrll+[Num] where [Num] is a number key from 0 to 9. To restore the viewport, press the [Num] key.

The effect of the left and right mouse buttons depends on the tool that is currently selected. The left mouse button is the main tool button and the right button is an alternate button. For example, using the select tool you can select vertices and faces with the left mouse button and unselect them with the right mouse button. By middle-clicking and dragging you can drag the viewport left, right, up, and down. Using the scroll wheel will zoom in or out.

The active viewport (the viewport under the mouse) will have a slightly lighter background color than the others. Some keyboard shortcuts will modify the selected viewport. For example + and - will zoom in and out. 0 (zero) will center the viewport on the origin. The backslash will flip an orthographic view to the opposite side (front view will become a back view). The backtick (left quote) will switch an orthographic view to a perspective view.

mm3d-master/doc/html/olh_mainwin.page000066400000000000000000000000651324021725400200630ustar00rootroot00000000000000PAGE_TITLE=Main Window PAGE_CONTENT=Material Details

Overview

A material defines how light reflects off of faces in a group. This includes the color of the faces and a texture map. A group can have only one material applied. The same material may be applied to more than one group.

Creating a Material

A material can be created using the Materials Window. You can open the Materials Window from the Materials menu, or by selecting one or more faces and then clicking the "..." button under "Group Materials" (note that you must have a group assigned to the faces for this to work.

Once you have opened the Materials Window, click "New Material..." and enter a name for the material. If you want to apply a 2D image texture map, click the "Set Texture" button.

Note that textures filenames in MM3D are saved relative to the directory in which the model is saved. It is a good idea to copy your image into the model directory or a sub-directory from where the model is.

If you are editing a texture file with a paint program while MM3D is running you can reload the texture using the "Reload Textures" option in the Materials menu.

Other Material Details

When changing the material that is applied to faces using the Group Properties panel, be aware that changing the material for the selected faces applies this change to all faces in the group, not just the selected ones.

To change the way the texture is mapped onto the faces of the group you will need to move the Texture Coordinates. Sometimes using a Texture Projection gives you a good starting point for texture coordinate assignment.

See Also

mm3d-master/doc/html/olh_materialdetails.page000066400000000000000000000001021324021725400215550ustar00rootroot00000000000000PAGE_TITLE=Material Details PAGE_CONTENT=Merge Window

Overview

The Merge Window allows you to merge a model file into the current model. After selecting a model file you will be prompted with the merge window to specify the location of the new model in the existing model as well as options for importing textures and animations.

Merge Location

The merge location frame is made up of two components, the Rotation and Translation components.

The Rotation specifies how the new model will be rotated relative to the existing model. You can rotate the new model on all three axes. Rotation is specified in degrees.

The Translation specifies the location of the new model relative to the origin of the existing model. The translation is specified in GL units. The relative position will depend on the scale of your model.

Merge Options

The Include textures checkbox allows you to specify if textures from the new model should be merged into the existing model.

The Include animations checkbox allows you to specify if animations from the new model should be merged into the existing model. If this checkbox is selected, you can also specify Animation Options

Animation Options

The Append animations checkbox will make the animations of the existing model and animations of the new model separate animations. Both models will appear in each others animations, but only one will animate. This only applies to the merge. After the models are merged you may modify the existing animations to animate both models.

The Merge if possible checkbox will attempt to combine the existing animations of both models so that both models are animated in each animation. In order to merge animations you must have the same number of animations in each model and the frame counts of the corresponding animations must also match (if model A has animations with 10, 15, and 12 frames, and model B has animations with 10, 15, and 12 frames they can be merged). Skeletal and Frame animations are merged independently. If you have a model which contains both types of animations and one type can be merged and the other cannot, the mergeable type will be merged.

Note that you can merge skeletal animations using the Animation Sets window even after the model has been merged. Frame animations cannot be merged through the Animations Sets window.

Press Ok to merge the new model into the current model or press Cancel to abort the merge.

mm3d-master/doc/html/olh_mergewin.page000066400000000000000000000000671324021725400202400ustar00rootroot00000000000000PAGE_TITLE=Merge Window PAGE_CONTENT=Mesh Details

Overview

A mesh is a collection of triangles that are connected by common vertices. If every edge of every triangle in the mesh is connected to another triangle in the mesh (there are no gaps or holes in the mesh) the mesh is called an "enclosed mesh".

Meshes are not first-class objects to Misfit Model 3D, but there are some operations where use of the term mesh can be helpful.

Note that the term "mesh" is distinct from "group". The term "group" in MM3D generally refers to a collection of triangles that have been defined as a group and may have a material applied. Triangles in a mesh may or may not be in a group.

Creating a Mesh

Meshes are created when you use the creation tools to create geometric shapes such as cubes, spheres, or cylinders.

Other Mesh Details

You can combine meshes using the Boolean Operataions panel. For the union, intersection, and subtraction operations to work properly, all meshes involved must be enclosed (otherwise the behavior of the face-removal step is undefined). If the meshes are not enclosed you can still use the fuse operation and manually remove the faces that must be removed.

The Simplify Mesh command is useful for combining faces that do not add detail to a shape. For example if you have a cube where each side is made up of 8 triangles, then all of these triangles are in the same plane and many edges form a single straight line. In this case, the eight faces on each side can be reduced to two faces. Often when you use a boolean operation to combine two objects you will want to use the simplify mesh command to eliminate unecessary faces from the model.

If you have mesh that is not enclosed you can use the Cap Holes command to create faces to fill in the gaps. Note that the cap holes feature is very limited. If your shape is relatively complex it may have difficulty correctly determining how to connect faces to fill in the gaps.

See Also

mm3d-master/doc/html/olh_meshdetails.page000066400000000000000000000000721324021725400207210ustar00rootroot00000000000000PAGE_TITLE=Mesh Details PAGE_CONTENT=Model Meta Data Window

The Model Meta Data Window is used to add or remove information associated with a model that does not affect rendering. This can include any arbitrary text data such as the name of the creator, copyright information, URLs, etc.

The main component of the window is the Name/Value list box. This list box contains name and value pairs.

To add a new name/value pair click the New button. A new Name/Value row will appear. You can edit the name and value by pressing the Enter key or by double-clicking on the name or value with the mouse. Names do not need to be unique, though duplicate names may be confusing for other people using this model.

To remove a name/value pair from the model, select the name in the list box and click the Delete button.

Press Ok to keep your changes or press Cancel to ignore any changes.

mm3d-master/doc/html/olh_metawin.page000066400000000000000000000001001324021725400200530ustar00rootroot00000000000000PAGE_TITLE=Model Meta Data Window PAGE_CONTENT= MM3D File Format

Contents

Overview

This document describes version 1.7 of the MM3D file format. Data that is available only in specific versions will be noted below. All other data is common to every version of the file format. Previous releases of Misfit Model 3D that do not read all data segments should still be able to load model files, though some information may be lost.

The MM3D file format was designed to be easy to extend and easy to read to extract just the information you want. The header will tell you what information is included in the file and give you offsets to the location where the information is in the file.

Data sections have their own header before the data. Each data type is either a fixed size or a variable size. If the data size is fixed (constant, Type B) the data size immediatley precedes the data block of the data section. If the data size is variable (Type A) the data size precedes each data element.

MM3D uses Intel byte order (least significant byte first). Bytes are 8 bits. The types specified in the Type fields below are ints (signed integers) or uints (unsigned integers). The type designation is followed by a number which designates the number of bits in that integer. The type may be multiplied by a constant or variable number to get the full length of the field. Variables are generally data fields from earlier sections in the file. In the data chunks there is also a float32 which is a 32-bit floating point number and an ASCIIZ which is every byte up to and including the next null byte. ASCIIZ strings are truncated to 1024 bytes (including the terminating null) if necessary.

As of MM3D version 1.4 all text strings are encoded as UTF-8. Versions 1.2 and earlier used extended ASCII encoding. If you want your MM3D models to be usable in new and older versions of MM3D you should use only standard ASCII characters (0-127) for model object names and texture filenames.

File Header

The file header is 12 bytes.

Data Type Notes Description
MAGIC_NUMBER int8 * 8 'MISFIT3D' If the first 8 bytes do not match this string it is not an MM3D file
MAJOR_VERSION uint8 0x01 Major version number, the file format may be incompatible with newer or older filters if the major version number does not match
MINOR_VERSION uint8 0x07 Minor version number, older filters should be able to get useful data from the file but may not understand the value of all flags or data segments
MODEL_FLAGS uint8 0x00 (reserved) Currently there are no model-wide flags, this byte is reserved in case such flags are ever needed
OFFSET_COUNT uint8   This is the number of data segments. It tells you how many offsets are in the next section of the file

Data Offsets

Data offsets are 6 bytes each. The value of [OFFSET_COUNT] in the header specifies how many data offsets are in this section.

The data offsets section is [OFFSET_COUNT] instances of:

Data Type Description
OFFSET_TYPE uint16 Type of data for this offset (types listed in the next section)
OFFSET_VALUE uint32 Offset to the data segment for this type (offset is from the start of the file)

Data Offset Types

The following is a list of known data segment types. Types are 16 bits. Bit 15 (0x8000) is a "uniform" flag, meaning data of that type is a fixed (constant) size.

Bit 14 (0x4000) is the dirty flag. If Mifit Model 3D encounters a data segment it does not understand it will keep a copy of the raw data and write that data to a file if the model is saved again. It will add the dirty bit to indicate to other model readers that this data was written by a version of the program that did not understand the data. It is therefore "dirty" and may be inconsistent with the model. Under these circumstances the reader may chose to discard the data or attempt to verify and use it.

The end of file offset is a special offset and indicates the file size. You should always check this value against the file size to be certain that the file is complete. There is no data at the end of file offset.

Type A (variable)

Type A Version Description
0x1001 1.4+ Meta data
0x1002   Unknown type information (not implemented)
0x0101   Groups
0x0141   Embedded textures (not implemented)
0x0142   External textures
0x0161   Materials
0x016c 1.6+ Texture Projections Triangles
0x0191 1.4+ Canvas Background Images
0x0301   Skeletal Animations
0x0321   Frame Animations
0x0326 1.6+ Frame Animation Points
0x0341   Frame Relative Animations (not implemented)
0x3fff   End of file (offset is file size)

Type B (fixed)

Type B Version Description
0x8001   Vertices
0x8021   Triangles
0x8026   Triangle Normals
0x8041   Joints
0x8046   Joint Vertices
0x8061 1.6+ Points
0x8106 1.4+ Smoothness Angles
0x8146 1.6+ Weighted Influences
0x8168 1.6+ Texture Projections (sphere/cylinder map)
0x8121   Texture Coordinates

User Defined Blocks

Types 0x0000 through 0x1fff are reserved for Misfit Model 3D defined types. 0x4000 through 0xffff are reserved for the uniform and dirty bit versions of each type. If you want to add a type for your own use it is recommended that you use a value in the 0x2000 through 0x2fff range. Suggestions for types which may be useful to other uses are welcome and may be incorporated into future versions.

Data Blocks

Data Blocks have a header and a data chunk. The data blocks are similar between types A and B. The only difference is how the size of each data element is handled. In Type A the size is included before each data element in the data chunk. In Type B the size is included at the end of the header and before the data chunk itself.

The size of a data element may change. When reading data from an MM3D file it is important to note if the size of the element is different from the expected size. If it is smaller, data at the end of the element has been omitted. If larger, data has been appended to the end of the element's data type and must be skipped over during data parsing. These situations may happen if your filter is reading a file written by a newer or older version of Misfit Model 3D. Data size changes will be rare but should be accounted for.

Type A

Data header:

Data Type Description
DATA_FLAGS uint16 Flags for the data segment (currently unused, should be 0x0000)
DATA_COUNT_A uint32 The number of elements in each data chunk

Data chunk:

Data Type Description
DATA_SIZE_A uint32 Size of this element of data
DATA_CHUNK_A uint8 * [DATA_SIZE_A] One element of [DATA_SIZE_A] size, Data Block Types are defined below

Type B

Data header:

Data Type Description
DATA_FLAGS uint16 Flags for the data segment (currently unused, should be 0x0000)
DATA_COUNT_B uint32 The number of elements in each data chunk
DATA_SIZE_B uint32 Size of each element of data

Data chunk:

Data Type Description
DATA_CHUNK_B uint8 * [DATA_SIZE_B] * [DATA_COUNT_B] [DATA_COUNT_B] elements of [DATA_SIZE_B] size, Data Block Types are defined below

Data Block Types

Meta Data

Version 1.4 and later.

The meta data section contains key/values pairs of ASCIIZ strings. These key/value pairs do not affect model display in any way. These are purely informational strings for things like copyright, contact, URLs, etc.

Keys are case-sensitive and do not have to be unique (though having two identical keys is bad form).

Data Version Type Description
META_KEY 1.4+ ASCIIZ Key for this meta data key/value pair
META_VALUE 1.4+ ASCIIZ Value associated with meta data key

Vertices

Data Type Description
VERTEX_FLAGS uint16 See vertex flags below
VERTEX_COORD_X float32 X coordinate of the vertex
VERTEX_COORD_Y float32 Y coordinate of the vertex
VERTEX_COORD_Z float32 Z coordinate of the vertex

Vertex flags:

Bits Version Data Description
0   Hidden Set if hidden, clear if visible
1   Selected Set if selected, clear if unselected
2 1.6+ Free Vertex Set if vertex does not have to be connected to a face (don't auto-delete when face is deleted)

Triangles

The triangles section describes the triangular faces of the model. The vertex indices are 0-based indices into the vertex array from the vertices section.

Data Type Description
TRIANGLE_FLAGS uint16 See triangle flags below
TRIANGLE_VERTEX_1 uint32 Index of vertex 1 of the triangle
TRIANGLE_VERTEX_2 uint32 Index of vertex 2 of the triangle
TRIANGLE_VERTEX_3 uint32 Index of vertex 3 of the triangle

Triangle flags:

Bits Data Description
0 Hidden Set if hidden, clear if visible
1 Selected Set if selected, clear if unselected

Triangle Normals

Version 1.4 and later.

The triangle normals section describes the normals for each face of the model. Each block is composed of a triangle index that indicates to which triangle the normals apply to, followed by three sets (one for each triangle vertex) of three floating point numbers (one for each dimension).

Data Version Type Description
TRI_NORM_FLAGS 1.4+ uint16 Reserved, should be 0
TRI_NORM_INDEX 1.4+ uint32 Triangle index (0 based)
TRI_NORM_V1_NORM 1.4+ float32 * 3 Normals for vertex 1 (XYZ)
TRI_NORM_V2_NORM 1.4+ float32 * 3 Normals for vertex 2 (XYZ)
TRI_NORM_V3_NORM 1.4+ float32 * 3 Normals for vertex 3 (XYZ)

Joints

The joint section describes joints used for skeletal animations. Their orientation information is relative to their parent joint's orientation.

Data Type Description
JOINT_FLAGS uint16 See joint flags below
JOINT_NAME int8 * 40 Joint name
JOINT_PARENT uint32 Index of parent joint
JOINT_LOCAL_ROT_X float32 X rotation of joint relative to parent (in radians)
JOINT_LOCAL_ROT_Y float32 Y rotation of joint relative to parent
JOINT_LOCAL_ROT_Z float32 Z rotation of joint relative to parent
JOINT_LOCAL_TRANS_X float32 X offset of joint relative to parent (or origin if root joint)
JOINT_LOCAL_TRANS_Y float32 Y offset of joint relative to parent
JOINT_LOCAL_TRANS_Z float32 Z offset of joint relative to parent

Joint flags:

Bits Data Description
0 Hidden (ingored) Set if hidden, clear if visible
1 Selected Set if selected, clear if unselected

Joint Vertices

The joint vertices section associates vertices with joints.

NOTE: As of version 1.6 this data is deprecated. Use the Weighted Influences data instead. This data section is maintained for backwards compatibility. Newer files should have this data and the Weighted Influences data. If the Weighted Influences section is present it takes precedence over this data. When writing this data, only one joint per vertex is allowed. The joint with the most influence (highest weight) on the vertex is the joint index that should be used.

Data Type Description
VERTEX_INDEX uint32 Index into vertex array
JOINT_INDEX uint32 Index into joint array for this vertex

Points

Version 1.6 and later.

Points are objects that have a position and orientation. They can be attached to bone joints for animation purposes. Points do not affect model geometry in any way. They are simply reference objects for specifying a location in the model. One potential use for this is bolt points for attaching one model to another (such as tags in MD3 models).

Note that the POINT_JOINT element is deprecated. It should still be set in MM3D files (or -1 if no bone joint assignment). If the point is assigned to multiple bone joints, the joint with the most influence (highest weight) should be used. When reading MM3D files, the POINT_JOINT element should usable, but any data in the Weighted Influences section takes precedence over this value.

Data Type Description
POINT_FLAGS uint16 See point flags below
POINT_NAME int8 * 40 Point name
POINT_TYPE int32 Type of point (reserved, should be zero)
POINT_JOINT int32 Index of parent joint (deprecated, use Weighted Influences)
POINT_ROT_X float32 X rotation of point (in radians)
POINT_ROT_Y float32 Y rotation of point
POINT_ROT_Z float32 Z rotation of point
POINT_TRANS_X float32 X position of point
POINT_TRANS_Y float32 Y position of point
POINT_TRANS_Z float32 Z position of point

Point flags:

Bits Data Description
0 Hidden (ingored) Set if hidden, clear if visible
1 Selected Set if selected, clear if unselected

Smoothness Angles

Version 1.4 and later.

Defines the maximum angle at which triangle edges in a group will be averaged for normal calculation. If two triangles share an edge that is greater than this angle, the edge will appear sharp rather than rounded.

Data Version Type Description
GROUP_INDEX 1.4+ uint32 Index into group array
ANGLE 1.4+ uint8 Maximum angle (in degrees) to use in smoothing normals (0-180)

Groups

The groups section groups faces (triangles) for editing or texturing purposes. Textures are applied to groups, so faces must be grouped in order to have a texture applied.

Data Type Description
GROUP_FLAGS uint16 See group flags below
GROUP_NAME ASCIIZ Name of the group of faces
TRIANGLE_COUNT uint32 Number of triangles in the group
TRIANGLE_INDICES uint32 * [TRIANGLE_COUNT] Index of each triangle belonging to the group
GROUP_SMOOTHNESS uint8 Determines how the face normals are interpolated between faces. 0 = flat along face plane, ff=averaged between all planes that share the vertex
GROUP_MATERIAL uint32 Index into material list (0xffffffff for none)

Group flags:

Bits Data Description
0 Hidden (ingored) Set if hidden, clear if visible
1 Selected Set if selected, clear if unselected

Weighted Influences

Version 1.6 and later.

The weighted influences section describes how vertices and points are assigned to bone joints. Objects can be assigned to multiple bone joints. This is the preferred method to save and load bone joint assignments for vertices and points. New versions of Misfit Model 3D will use this data if it is present and the deprecated data sections if this data is not present.

The type of influence can be automatic (based on the position of the object relative to the bone joint), remainder (100 minus the sum of all other joint weights), or custom (manually entered by the user). If the type is "Remainder" and the sum of the influence of other joints is greater than 100, the remainder value is 0 (it is never negative).

The weight of each influence ranges from 0 to 100. The relative influence of each joint is the percentage of the total influence of all joints. The sum off all influence weights does not have to be 100. For example a single joint with a weight of 80 will have 100% influence. Two joints that each have a weight of 80 will each have 50% influence. One joint with a weight of 40 and another with a weight of 80 will have 33% and 67% influence respectively.

Data Type Description
POS_TYPE uint8 Type of object influenced by joint (see position types below)
POS_INDEX uint32 Index into vertex or point array (based on position type)
INF_INDEX uint32 Bone joint index
INF_TYPE uint8 Type influence by joint (see influence types below)
INF_WEIGHT int8 Weight of this joint's influence (0 to 100)

Position Types:

Number Version Type
0 1.6+ Vertex
2 1.6+ Point

Influence Types:

Number Version Type
0 1.6+ Custom (manually entered by user)
1 1.6+ Automatic
2 1.6+ Remainder

Texture Projections

Version 1.6 and later.

The texture projection section describes objects that map triangle texture coordinates onto a texture as a cylinder or sphere. The "up" vector defines which direction is the U component of the texture projection. In some cases (such as cylinder) the magnitude of this vector determines the size of the projection area. The "seam" vector indicates where the V texture component starts and 0.0 and wraps back to 0.0 after reaching 1.0.

Data Type Description
PROJ_FLAGS uint16 See projection flags below
PROJ_NAME int8 * 40 Projection name
PROJ_TYPE int32 Type of Projection (see types below)
PROJ_POS_X float32 X coordinate of projection center
PROJ_POS_Y float32 Y coordinate of projection center
PROJ_POS_Z float32 Z coordinate of projection center
PROJ_UPVEC_X float32 X component of up vector
PROJ_UPVEC_Y float32 Y component of up vector
PROJ_UPVEC_Z float32 Z component of up vector
PROJ_SEAMVEC_X float32 X component of seam vector
PROJ_SEAMVEC_Y float32 Y component of seam vector
PROJ_SEAMVEC_Z float32 Z component of seam vector
PROJ_MIN_U float32 Minimum U texture coordinate
PROJ_MIN_V float32 Minimum V texture coordinate
PROJ_MAX_U float32 Maximum U texture coordinate
PROJ_MAX_V float32 Maximum V texture coordinate

Projection flags:

None

Projection types:

Number Version Type
0 1.6+ Cylinder
1 1.6+ Sphere

Texture Coordinates

The texture coordinates section maps the vertices of a triangle onto a material's texture. Texture coordinates range from (0.0, 0.0) to (1.0, 1.0). The origin (0,0) of a texture is the lower-left corner, not the upper-left. Values outside of the 0.0 to 1.0 range are valid.

Data Type Description
TEXCOORD_FLAGS uint16 Unused
TEXCOORD_TRIANGLE uint32 Triangle for this texture coordinate set
TEXCOORD_VERTEX_1_S float32 S (x) coordinate for triangle vertex 1
TEXCOORD_VERTEX_2_S float32 S (x) coordinate for triangle vertex 2
TEXCOORD_VERTEX_3_S float32 S (x) coordinate for triangle vertex 3
TEXCOORD_VERTEX_1_T float32 T (y) coordinate for triangle vertex 1
TEXCOORD_VERTEX_2_T float32 T (y) coordinate for triangle vertex 2
TEXCOORD_VERTEX_3_T float32 T (y) coordinate for triangle vertex 3

External textures

The external textures section describes the textures in the model. The textures are assigned to materials which describe the lighting properties. Groups reference materials. One texture may be referenced by many materials.

Data Type Description
TEXTURE_FLAGS uint16 Flags for texture (unused)
TEXTURE_PATH ASCIIZ File path to texture relative to model (directory separator is backslash)

Materials

The materials section describes the materials in the model. The materials reference textures and describe the lighting properties. Groups reference materials. Some materials do not have textures. For materials without textures, the MATERIAL_TEXTURE element is still present but the value is ignored. The MATERIAL_FLAGS element indicates if the material has a texture (see below).

Data Type Description
MATERIAL_FLAGS uint16 See material flags below
MATERIAL_TEXTURE uint32 Texture index for this material
MATERIAL_NAME ASCIIZ Name of the material
MATERIAL_AMBIENT float32 * 4 Ambient light properties (RGBA)
MATERIAL_DIFFUSE float32 * 4 Diffuse light properties (RGBA)
MATERIAL_SPECULAR float32 * 4 Specular light properties (RGBA)
MATERIAL_EMISSIVE float32 * 4 Emissive light properties (RGBA)
MATERIAL_SHININESS float32 Shininess

Material flags:

The Clamp S and Clamp T values specify whether texture coordinates outside of the 0.0 to 1.0 range should wrap or not. If the bit is set, the texture wraps. If the bit is clear the colors at the edge of the texture are stretched.

Bits Version Data Description
0-3   Material type 0 = external texture, 15 = Blank (no texture, only lighting), 1-14 = reserved
4 1.4+ Clamp S Clamp S texture coordinates (do not tile/repeat)
5 1.4+ Clamp T Clamp T texture coordinates (do not tile/repeat)

Texture Projection Triangles

Version 1.6 and later.

The texture projection triangles section is a list of which triangles are using a specified texture projection to set their texture coordinates.

Data Type Description
PROJ_INDEX uint32 Texture Projection Index to which these triangles are assigned
TRI_COUNT uint32 Number of triangles assigned to this projection
TRI_INDICES uint32 * [TRI_COUNT] List of triangle indices that are assigned to projection

Canvas Background Images

Version 1.4 and later.

The Canvas Background Image section describes background images that appear in canvas views. There can be one background image for each of the six canvas views (Front, Back, Left, Right, Top, Bottom) and each can be scaled and positioned independently. Canvas background images are for editing purposes only and should not be rendered as part of the model itself.

Data Version Type Description
CANVBACKIMAGE_FLAGS 1.4+ uint16 Reserved, should be 0
CANVBACKIMAGE_VIEWINDEX 1.4+ uint8 View direction (see below)
CANVBACKIMAGE_SCALE 1.4+ float32 Image scale (1.0 = center to top/left is 1.0 OpenGL unit)
CANVBACKIMAGE_CENTER 1.4+ float32 * 3 Center coordinates of image
CANVBACKIMAGE_FILENAME 1.4+ ASCIIZ Filename of the image to load (relative path)

Canvas Background Image View Directions

View Index Version Direction
0 1.4+ Front
1 1.4+ Back
2 1.4+ Left
3 1.4+ Right
4 1.4+ Top
5 1.4+ Bottom

Skeletal Animations

The skeletal animations section describes the skeletal animations in the model. It includes all frames of all skeletal animations. This mostly consists of animation data and joint keyframes.

Data Type Description
SKEL_FLAGS uint16 See skeletal animation flags below
SKEL_NAME ASCIIZ Name of animation
SKEL_FPS float32 Frames per second
SKEL_FRAME_COUNT uint32 Number of frames in animation
SKEL_FRAME_DATA SKEL_FRAME_TYPE * [SKEL_FRAME_COUNT] Frame data for skeletal animation, see below

Skeletal animation flags:

Bits Version Data Description
0 1.7+ Loop If set it's a looping aniamtion, if clear it's non-looping

Skeletal frame data type:

Data Type Description
SKEL_KEYFRAME_COUNT uint32 Number of joint keyframes for this skeletal animation frame
SKEL_KEYFRAME_DATA SKEL_KEYFRAME_TYPE * [SKEL_KEYFRAME_COUNT] Keyframe data for this frame, see below

Skeletal keyframe data type:

Data Type Description
SKEL_KEYFRAME_JOINT uint32 Joint that this keyframe is for
SKEL_KEYFRAME_ANIM_TYPE uint8 Keyframe type: 0 = translation, 1 = rotation
SKEL_KEYFRAME_POS_X float32 X position data (translation or rotation [in radians])
SKEL_KEYFRAME_POS_Y float32 Y position data
SKEL_KEYFRAME_POS_Z float32 Z position data

Frame Animations

The frame animations section describes the frame animations in the model. It includes all frames of all frame animations. This mostly consists of animation data and vertex positions for each animation frame (each frame is vertex positions for every vertex in the model).

Data Type Description
FRAME_FLAGS uint16 See frame animation flags below
FRAME_NAME ASCIIZ Name of animation
FRAME_FPS float32 Frames per second
FRAME_COUNT uint32 Number of frames in animation
FRAME_DATA FRAME_ANIM_DATA * [FRAME_COUNT] Vertex position data for each frame, see below

Frame animation flags:

Bits Version Data Description
0 1.7+ Loop If set it's a looping aniamtion, if clear it's non-looping

Frame animation frame data type:

Data Type Description
FRAME_VERTEX_DATA FRAME_VERTEX_TYPE * [VERTEX_COUNT] Vertex position data for each vertex in this frame, see below

Frame animation vertex data type:

Data Type Description
FRAME_VERTEX_COORD_X float32 X coordinate for vertex
FRAME_VERTEX_COORD_Y float32 Y coordinate for vertex
FRAME_VERTEX_COORD_Z float32 Z coordinate for vertex

Frame Animation Points

Version 1.6 and later.

The frame animations points section describes the location and rotation of points in frame animations.

Data Type Description
FPOINT_FLAGS uint16 Flags for skeletal animation (unused)
FPOINT_ANIM uint32 Index of frame animation
FPOINT_FRAME_COUNT uint32 Number of frames that follow
FPOINT_POINT_DATA FPOINT_FRAME_DATA * [FPOINT_FRAME_COUNT] * [POINT_COUNT] Point position and rotation data for each frame, see below

There is one of these data structures for each point for each animation frame. Frame animation point data type:

Data Type Description
FPOINT_ROT_X float32 X rotation of point (in radians)
FPOINT_ROT_Y float32 Y rotation of point
FPOINT_ROT_Z float32 Z rotation of point
FPOINT_TRANS_X float32 X position of point
FPOINT_TRANS_Y float32 Y position of point
FPOINT_TRANS_Z float32 Z position of point

Example Hex Dump

This is an example hex dump of a cube with grouped faces. It is color-coded to highlight the different parts of the file.

Key:

  • File header green
  • Offsets blue
  • Vertices dark red
  • Faces magenta
  • Groups light red
0000000: 4d49 5346 4954 3344 0101 0004 0180 2400 MISFIT3D......$.
0000010: 0000 2180 9e00 0000 0101 5001 0000 ff3f ..!.......P...?
0000020: a001 0000 0000 0800 0000 0e00 0000 0200 ................
0000030: 0000 803f 0000 80bf 0000 803f 0200 0000 ...?.......?....
0000040: 80bf 0000 80bf 0000 803f 0200 0000 803f .........?.....?
0000050: 0000 803f 0000 803f 0200 0000 80bf 0000 ...?...?........
0000060: 803f 0000 803f 0000 0000 80bf 0000 80bf .?...?..........
0000070: 0000 80bf 0000 0000 803f 0000 80bf 0000 .........?......
0000080: 80bf 0000 0000 80bf 0000 803f 0000 80bf ...........?....
0000090: 0000 0000 803f 0000 803f 0000 80bf 0000 .....?...?......
00000a0: 0c00 0000 0e00 0000 0000 0300 0000 0100 ................
00000b0: 0000 0000 0000 0000 0000 0000 0200 0000 ................
00000c0: 0300 0000 0000 0700 0000 0500 0000 0400 ................
00000d0: 0000 0000 0400 0000 0600 0000 0700 0000 ................
00000e0: 0000 0200 0000 0000 0000 0500 0000 0000 ................
00000f0: 0500 0000 0700 0000 0200 0000 0000 0600 ................
0000100: 0000 0400 0000 0100 0000 0000 0100 0000 ................
0000110: 0300 0000 0600 0000 0000 0700 0000 0600 ................
0000120: 0000 0300 0000 0000 0300 0000 0200 0000 ................
0000130: 0700 0000 0000 0000 0000 0100 0000 0400 ................
0000140: 0000 0000 0400 0000 0500 0000 0000 0000 ................
0000150: 0000 0100 0000 4600 0000 0000 6772 6f75 ......F.....grou
0000160: 7020 6e61 6d65 000c 0000 0000 0000 0001 p name..........
0000170: 0000 0002 0000 0003 0000 0004 0000 0005 ................
0000180: 0000 0006 0000 0007 0000 0008 0000 0009 ................
0000190: 0000 000a 0000 000b 0000 00ff ffff ffff ...........
mm3d-master/doc/html/olh_mm3dformat.page000066400000000000000000000000751324021725400204730ustar00rootroot00000000000000PAGE_TITLE=MM3D File Format PAGE_CONTENT=MS3D Export Options

The MS3D Export Options window is displayed when you save a model in MS3D format. It allows you to specify how you want bone joint influences to be saved.

The Format Subversion options specify which MS3D subversion you want to save as. If no vertices in your model are assigned to more than one bone joint, select Subversion 0. Otherwise, select Subversion 1 or 2.

  • Subversion 0 - Original file format, a vertex can only be assigned to one bone joint.
  • Subversion 1 - A vertex may be assigned to multiple bone joints, the weight range is 0 to 255.
  • Subversion 2 - A vertex may be assigned to multiple bone joints, the weight range is 0 to 100.

The Subversion Options section includes options that only apply to specific subversions. The Vertex Extra option is a 32-bit number that is saved with the vertex data in Subversion 2. The number is specified in hexadecimal. The number supplied is used for all vertices. There is no way to set this value for individual vertices.

Click Ok to save the model with the specified options or click Cancel to ignore any changes.

mm3d-master/doc/html/olh_ms3dprompt.page000066400000000000000000000001001324021725400205170ustar00rootroot00000000000000PAGE_TITLE=MS3D Export Options PAGE_CONTENT=Normal Details

Overview

A normal is line that is perpendicular to the plane of a triangle. The normal is used to perform lighting reflection calculations and determine whether a triangle faces toward the camera or away from the camera.

If faces are connected to each other, the normals can be averaged to make the edges where they connect appear smooth. You cannot directly manipulate a face's normal, but you can influence the averaging calculations by assigning faces to a group and then changing the group properties. See the Group Window for details.

You can invert the normals of selected faces using the Invert Normals command. If some or all normals in a mesh are facing the wrong direction (pointing inward) and the faces are part of an enclosed mesh, you can use the Normals Face Out command to make all normals point outward. If the triangles are not part of an enclosed mesh the behavior is undefined.

See Also

mm3d-master/doc/html/olh_normaldetails.page000066400000000000000000000000761324021725400212610ustar00rootroot00000000000000PAGE_TITLE=Normal Details PAGE_CONTENT=OBJ Export Options

The OBJ Export Options window is displayed when you save a model in OBJ format. It allows you to specify things like whether or not to save the normals in the file and what level of precision you want (which affects overall file size).

The Save Normals checkbox allows you indicate if you want the normals saved in the file or not.

The Vertex Decimal Places input box allows you specify the precision of the vertex coordinates. The number shown indicates how many numbers will follow after the decimal point.

The Texture Decimal Places input box allows you specify the precision of the texture coordinates. The number shown indicates how many numbers will follow after the decimal point.

The Normal Decimal Places input box allows you specify the precision of the triangle normals. The number shown indicates how many numbers will follow after the decimal point.

Click Ok to save the model with the specified options or click Cancel to ignore any changes.

mm3d-master/doc/html/olh_objprompt.page000066400000000000000000000000761324021725400204370ustar00rootroot00000000000000PAGE_TITLE=OBJ Export Options PAGE_CONTENT=Paint Texture Window

The Paint Texture Window is used to create an image file with faces from the model projected onto it. You can then use a paint program of your choice to draw in the contents of your texture. This window uses the texture coordinates that are already assigned to the faces using the Texture Coordinates Window or the Texture Projection Window.

To use the Paint Texture Window select the faces to be painted onto a texture and then select Paint Texture... from the Materials menu.

The Polygons option allows you to define how the polygons should be drawn (filled or empty, with or without lines).

The Vertices option allows to turn drawing of the vertices on and off.

The Save Size options allow you to specify the width and height of the texture to save.

When you are done changing the texture options, select Save Texture... to select a file name to save as, or select Close to close the window without saving a texture image file.

For more details on working with texture maps, see the Materials Window , the Groups Window, the Texture Coordinates Window, and the Texture Projection Window.

mm3d-master/doc/html/olh_painttexturewin.page000066400000000000000000000001061324021725400216670ustar00rootroot00000000000000PAGE_TITLE=Paint Texture Window PAGE_CONTENT=Plugins Window

The Plugins Window shows you what plugins are installed and active.

Plugins are located in a directory on your hard drive. On Unix-like systems, Misfit Model 3D will try $HOME/.mm3d/plugins. If that directory does not exist it will try in a shared directory (defaults to /usr/local/share/mm3d/plugins, although this can be changed at install time). Misfit will descend into subdirectories and follow symbolic links. On Windows, Misfit Model 3D uses the plugins subdirectory where Misfit Model 3D was installed.

The main component of the plugins window is a table that contains a list of plugins. Each plugin should also provide a Version string and a Description string. There is also a Status column that tells you if the plugin is properly initialized and currently active.

All plugins can be disabled at run time by specifying --no-plugins on the command line. Specific plugins can be disabled by specifying --no-plugin=plugin_name on the command line. --no-plugin can be specified more than once.

Press Ok to close the window.

mm3d-master/doc/html/olh_pluginwin.page000066400000000000000000000000721324021725400204330ustar00rootroot00000000000000PAGE_TITLE=Plugins Window PAGE_CONTENT=Point Details

Overview

A point is is an object that has a name, position, and rotation. It may be attached to up to four bone joint influences.

Points are not true geometric objects. They are simply place-holders in 3D space. A programmer may use a point to define a bolt point. The Quake MD3 filter uses points as "tags" for combining multiple model files into a single final model.

Creating a Point

Use the Create Point tool to create a pone joint.

Other Point Details

You can change the name of a point using the Name Properties panel or Points Window. You can assign bone joint influences to a point using the Influence Properties panel.

See Also

mm3d-master/doc/html/olh_pointdetails.page000066400000000000000000000000741324021725400211200ustar00rootroot00000000000000PAGE_TITLE=Point Details PAGE_CONTENT=Points Window

The Points Window can be opened by selecting Points... from the Geometry menu. The Points Window allows you to rename points and assign points to a bone joint. To create points, see the Create Point tool.

Points List

The points combo box lists all the points in the model. Selecting a point in the combo box will cause that point to be selected (all other points will be unselected). After selecting a point you can rename it, delete it, or assign it to a bone joint.

Rename

The Rename button allows you to rename a point. Point names do not have to be unique.

Delete

The Delete button deletes a point.

Bone Joint

The Bone Joint drop-down box lists all bone joints in the model. Select a bone joint to assign the point to the specified joint. Note that using the Influences Propertes Panel is more flexible than the Points Window when assigning bone joints.

Press Ok to keep your changes or press Cancel to ignore any changes.

See Also

mm3d-master/doc/html/olh_pointwin.page000066400000000000000000000000701324021725400202640ustar00rootroot00000000000000PAGE_TITLE=Points Window PAGE_CONTENT=Texture Projection Details

Overview

A Texture Projection helps you apply a 2D image texture map to a group of faces in a spherical or cylindrical fashion. There is a also a plane projection you can use if the Group Map scheme in the coordinate window is not aligned to the axis of your mesh.

A texture projection does not have a 2D texture associated with it. Any faces that use the texture projection to assign texture coordinates will use whatever texture is applied to their group.

Creating Texture Projections

Use the Create Projection tool to create a texture projection. After creating the projection, you can add faces to the the projection by selecting the faces and then selecting the "Texture Projection" from the Projection Properties panel, or by using the "Add Faces To Projection" button in the Projection Window.

Other Texture Projection Details

After creating the projection you can change the type of projection (sphere, cylinder, plane) Using the Projection Window or by selecting the Projection Type from the Projection Properties panel.

You can resize the projection by selecting it and then using the Scale Tool. You can rotate the projection using the Rotate Tool.

On the cylinder and sphere projections you will notice that one of the dashed lines is thicker than the others. This is the "seam", or the location where the texture coordinates wrap around the edges of the 2D texture. You can rotate the projection to change where the seam is applied to the mesh.

See Also

mm3d-master/doc/html/olh_projectiondetails.page000066400000000000000000000001161324021725400221400ustar00rootroot00000000000000PAGE_TITLE=Texture Projection Details PAGE_CONTENT=Texture Projection Window

The Texture Projection Window is used to adjust how a texture is applied to the faces of the model in a sphere or cylinder mapping. This window is used after you have created a texture projection with the Projection tool. The Texture Projection Window

To change the texture projection properties, select the projection you wish to modify and select Edit Projection in the Main Window's Materials menu.

The texture projection window allows you to change the projection type, rename the projection, adjust the UV range that the texture coordinates are mapped to, adjust where the seam (wrap point) is on the sphere or cylinder, and add or remove faces from the projection. It does not allow you to change individual vertex texture coordinates. If you want to move each vertex individually, use the Texture Coordinates Window.

The Texture Coordinates Window contains a drop-down box at the top of the window with the current projection name, a Texture Frame that shows how the faces are projected onto the texture, and various buttons to change the projection's properties.

The Texture Frame shows the texture used by the selected faces. Faces and vertices are drawn over the texture to show where each face's vertices are applied to the texture. There is also a white box that shows the UV range where the faces are mapped onto the texture.

You can modify the UV Range with the left mouse button. Click and drag on the edges or corners of the UV Range box to move resize the range. Click and drag inside the UV Range box to move the UV Range to a new location on the texture.

You can move the seam (the location where the texture wraps on the cylinder or sphere) by using the right mouse button. Click inside the UV Range box and drag to move the seam left or right. You will see faces wrap from one side of the UV Range box to the other.

You can pan around the Texture Frame by using the arrow buttons inside the frame window, or by middle-click dragging. You can zoom in or out by using the Zoom Buttons or by using the mouse scroll wheel.

Use the Type drop-down box to change the projection types.

Use the Rename button to rename the selected projection.

Use the Zoom Edit Box or Zoom Buttons (magnifying glasses) to zoom the texture view in or out.

The Apply Projection button remaps the faces on this projection to the projection location. Normally this is automatic when the projection is modified. You may need to use this button if you move the texture coordinates manually and want to restore them to the projection location without modifying the projection itself.

The Reset UV Range button sets the minimum and maximum UV coordinates to the edges of the texture (0.0 to 1.0).

The Add Faces to Projection button adds the selected faces in the main window to the projection in the Texture Projection Window.

The Remove Faces button removes the selected faces in the main window from the projection.

Press Close to close the Texture Projection Window.

See Also

mm3d-master/doc/html/olh_projectionwin.page000066400000000000000000000001111324021725400213030ustar00rootroot00000000000000PAGE_TITLE=Texture Projection Window PAGE_CONTENT=Properties Panel

Overview

The Properties Panel is a dockable window. It contains context-sensitive model data so that you can edit some model properties directly. For example, if you have the faces of a mesh selected, it will allow you to directly edit the center position as well as assign groups and materials.

To open the Properties Panel, select "View | Show Properties". To hide the Properties Panel, select "View | Hide Properties" or click the "X" in the upper-right corner of the panel.

The Properties Panel has several sub-panels that appear depending on what you have selected. Below is a table that lists which panels appear when various items are selected.

Selection Panel
Point or Bone Joint
(exactly one selected)
Name
Any Geometry Position (center)
Point or Bone Joint
(exactly one selected)
Rotation
Faces (triangles) Group
Texture Projections Projection
Vertices or Points
(if bone joints exist)
Influences

Name

The Name Panel has a text box with the name of the selected point or bone joint. You can change this text to change the name of the selection. This panel only appears if you have exactly one point or bone joint selected.

Position

The Position Panel has text boxes that list the center coordinates for the selected geometry. You can edit the position directly by changing these numbers.

Rotation

The Rotation Panel allows you to change the rotation of a point or a bone joint. The point rotation applies to non-animated points or points in a frame animation. The joint rotation only applies during skeletal animations (it sets a rotation keyframe).

Group

The Group Panel appears when you have one or more faces (triangles) selected. With this panel you can assign a group to the selected faces. You can select the material for the group (note that material assignments apply to the entire group; so this changes the material for all faces in the group, not just the selected faces). You can also select a Texture Projection for the selected faces if you want to apply a sphere or cylinder texture map.

Projection

The Projection Panel has a drop-down box that allows you to change the projection type. See Texture Projection Details for more information.

Influences

The Influences Panel appears when there are bone joints in the model and you have some geometry selected. With the Influences panel you can assign up to four bone joints to influence the movement of the selected geometry. See Bone Joint Details for more information.

mm3d-master/doc/html/olh_properties.page000066400000000000000000000000751324021725400206160ustar00rootroot00000000000000PAGE_TITLE=Properties Panel PAGE_CONTENT=Contents

Loading Skins and Textures

MD2 models should be about 44 GL units tall and centered on the origin.

MD2 skins are a bit tricky to load. In general the MD2 filter attempts to load skins in the following manner:

  • Load any skin image file specified in the model, assuming it is in the same directory as the model
  • If no skins are in the model, or no skins listed in the model could be loaded, the filter will try to load any image that begins with the characters in the model's filename (excepting the extension). So model.md2 would load any model*.* file in the same directory that the program has image filters for.
  • Quake uses PCX files for skins. Misfit will allow you to use any image format, but you should use PCX if you want others to be able to load your model.

When saving models as MD2 it is important to note that MD2 models only use one texture as a skin at any given time. All vertices of the model must be mapped to the same texture. You may include different colorings of the same texture for different skins and add those to the model as additional textures. Those textures should be available as alternate skins for the model.

Animations

MD2 animations specify vertex positions for each vertex for each frame of each animation. This can be tedious. When creating a model from scratch it is usually easier to save the model in MM3D format and create skeletal animations. Then when you are ready to export to MD2, convert the skeletal animations to frame animations using the Animation Sets Window and save as an MD2.

Because of the enormous overhead of saving undo information for animations upon insertion and deletion of vertex and face primitives, you are not allowed to add or remove primitives from a model that has frame animations. You may, however, merge another existing model into the one you are working on. This is another reason why it is best to work with MM3D files and skeletal animations and only export MD2 files when necessary.

Triangle Strips

MD2 files save triangle strip information for optimized model drawing. Misfit Model 3D is rather dumb about triangle strips by default and creates a triangle fan for each triangle. If you want smarter triangle strips see the ACTC triangle stripping plugin on the website.

Note that plugins are only available on Linux and Mac OS X systems. Plugin support is not available on Windows systems at this time.

mm3d-master/doc/html/olh_quakemd2.page000066400000000000000000000000721324021725400201300ustar00rootroot00000000000000PAGE_TITLE=Quake MD2 Notes PAGE_CONTENT=Contents

Model Types

An MD3 model contains a set of meshes and tags. Some in-game Quake models are actually composites of several MD3 files. For example, a player model consists of head.md3, upper.md3, and lower.md3 files. Tags within these files tell Quake how to assemble the model files into one single model.

Misfit Model 3D is capable of loading and saving a single MD3 file, or loading and saving all files in a player model as one model.

If you attempt to load a file named head.md3, upper.md3, or lower.md3 and the other two files are present, MM3D will ask you if you want to load all sections as a player model. Answer Yes to load all three files as one model. Answer No to load only the specified model file.

When you save a model, MM3D will ask to save as a player model if the following conditions are met. If any of the following conditions are not met, the model will be saved as a single MD3 file.

  • The saving file name is head.md3, upper.md3, or lower.md3
  • The model contains at least two points; named tag_torso and tag_head.
  • The model contains at least one group beginning with h_ (for head meshes), u_ (for upper body meshes), and l_ (for lower body meshes).
  • The MD3_composite metadata value is not set to 0 (zero)

If the model is saved as a player model the animation.cfg file will be created automatically. If the model is saved as a single file, no animation.cfg file will be created.

Skin files are read automatically for player and non-player models. Skin files are never created or modified by MM3D. If you wish to change or create a skin file you must do this step manually.

Player Models

A typical MD3 player model might be 60 GL units tall and 30 wide. The base of the feet should be at -24.

Player models consist of three model files: head.md3, upper.md3, and lower.md3. Usually these correspond to head, torso, and legs respectively. These three models are connected with tags (Points in MM3D). The weapon and Team Arena CTF flag the player is holding are also connected to the player model with a tag.

Typical tags for player models:
Model File Tags in model
head.md3 tag_head
upper.md3 tag_head, tag_torso, tag_weapon, (Team Arena) tag_flag
lower.md3 tag_torso

Other unknown tags will be saved in all model files which can be used by Quake 3 mods.

You can have multiple skins for a player model. Each md3 file should have a corresponding skin file (head_default.skin, lower_default.skin, upper_default.skin). Usually there are at least three skins for a player model: _default.skin, _red.skin, and _blue.skin. For more on skins see Skins and Textures.

Player models need an animation.cfg file to specify which frames correspond to in-game actions. An animation.cfg file might look like the example below. All animation sequences should have at least one frame.

Head models do not have animations in Quake 3. The head is attached to the tag_head tag in the upper body model. If you want to animate the head, you can hide the tag_head inside the model and do all the head animations in the torso (upper) meshes. You should still make a head model because it is displayed on the HUD.

It's possible to add support for head animations by modifying the Quake 3 code. MM3D supports ALL_ animation prefix for head/upper/lower animations and HEAD_ animation prefix for head-only animations.

The animation name affects which sections of the player the animation is exported to.
Animation Prefix Models
ALL_ upper.md3, lower.md3, head.md3
BOTH_ upper.md3, lower.md3
TORSO_ upper.md3
LEGS_ lower.md3
HEAD_ head.md3

Quake 3 player model animations must be in the same order as listed below. The optional Quake III: Team Arena animations at the end of the list require tag_flag tag in the upper model to be used in-game. It is recommended to set Loop for each animation as listed below in the Animation Panel. This controls whether the individual animations are marked as looping in the exported animation.cfg.
Animation Loop Description
BOTH_DEATH1 no Random death 1, for example twirl death.
BOTH_DEAD1 no Set animation frame count to 0 in MM3D to use last frame of BOTH_DEATH1.
BOTH_DEATH2 no Random death 2, for example other side twirl death.
BOTH_DEAD2 no Set animation frame count to 0 in MM3D to use last frame of BOTH_DEATH2.
BOTH_DEATH3 no Random death 3, for example backflip death.
BOTH_DEAD3 no Set animation frame count to 0 in MM3D to use last frame of BOTH_DEATH3.
TORSO_GESTURE no Taunt.
TORSO_ATTACK no Firing gun. This is synced with first person hand model and must have 6 frames.
TORSO_ATTACK2 no Guntlet punch. This is synced with first person hand model and must have 6 frames.
TORSO_DROP no Drop weapon. This is synced with first person hand model and must have 5 frames.
TORSO_RAISE no Raise weapon. This is synced with first person hand model and must have 4 frames.
TORSO_STAND no Holding gun.
TORSO_STAND2 no Holding gauntlet.
LEGS_WALKCR yes Walking while crouching. It is played in reverse when walking backward.
LEGS_WALK yes Walking forward. It is played in reverse when walking backward.
LEGS_RUN yes Running forward.
LEGS_BACK yes Running backward.
LEGS_SWIM yes Swimming.
LEGS_JUMP no Jump forward (jump off the ground).
LEGS_LAND no Jump forward (land).
LEGS_JUMPB no Jump backward (jump off the ground).
LEGS_LANDB no Jump backward (land).
LEGS_IDLE yes Idle standing.
LEGS_IDLECR yes Idle crouching.
LEGS_TURN yes Standing still and turning left or right.
TORSO_GETFLAG no Team Arena; give order to get flag.
TORSO_GUARDBASE no Team Arena; give order to guard base.
TORSO_PATROL no Team Arena; give order to patrol.
TORSO_FOLLOWME no Team Arena; give order to follow me.
TORSO_AFFIRMATIVE no Team Arena; confirm order.
TORSO_NEGATIVE no Team Arena; reject order.

Example animation.cfg

//Quake3 player animation file

sex m
footsteps normal

// first frame, num frames, looping frames, frames per second

0       32      0       25              // BOTH_DEATH1
32      1       0       25              // BOTH_DEAD1
32      35      0       20              // BOTH_DEATH2
67      1       0       20              // BOTH_DEAD2
68      25      0       25              // BOTH_DEATH3
93      1       0       25              // BOTH_DEAD3

94      39      0       15              // TORSO_GESTURE
133     7       0       15              // TORSO_ATTACK  (MUST NOT CHANGE -- hand animation is synced to this)
140     11      0       15              // TORSO_ATTACK2 (MUST NOT CHANGE -- hand animation is synced to this)
151     5       0       15              // TORSO_DROP    (MUST NOT CHANGE -- hand animation is synced to this)
156     6       0       15              // TORSO_RAISE   (MUST NOT CHANGE -- hand animation is synced to this)
162     31      0       10              // TORSO_STAND
193     11      0       10              // TORSO_STAND2

94      12      12      15              // LEGS_WALKCR
107     12      12      15              // LEGS_WALK
120     12      12      17              // LEGS_RUN
133     14      12      17              // LEGS_BACK
148     12      12      14              // LEGS_SWIM
159     6       0       8               // LEGS_JUMP
167     6       0       12              // LEGS_LAND
172     6       0       10              // LEGS_JUMPB
178     6       0       10              // LEGS_LANDB
185     6       6       5               // LEGS_IDLE
192     7       7       5               // LEGS_IDLECR
200     6       6       20              // LEGS_TURN

Player Metadata

Set MD3_CFG_* metadata to insert a keyword into the animation.cfg. For example, set MD3_CFG_sex meta data to value f to specify that the player model is female. Keywords and values are automatically detected when loading a player model. Any arbitraty keywords can be used. Keywords should not start with an animation prefix (ALL_, BOTH_, TORSO_, LEGS_, or HEAD_) as it may be detected as an animation when loaded by MM3D. Quake 3 only supports sex, footsteps, headoffset, fixedtorso, and fixedlegs. Example:

sex f // m, f, or n
footsteps normal // footstep sfx: normal, boot, flesh, mech, or energy
headoffset 0 0 0 // head offset when displayed on HUD
fixedtorso // don't rotate torso pitch when looking up or down
fixedlegs // don't rotate legs (always align with torso)

Set the MD3_AnimKeyword metadata value to 1 to list animation names at the beginning of line in animation.cfg. This is automatically detected when loading a player model. It is not supported by Quake 3. It is used by Elite Force Single Player and Turtle Arena. Example:

BOTH_DEATH1 0       32      0       25
BOTH_DEAD1  32      1       0       25

Set the MD3_NoSyncWarning metadata value to 1 to disabling writing sync warnings in animation.cfg for TORSO_ATTACK, TORSO_ATTACK2, TORSO_DROP, and TORSO_RAISE. It is used by Turtle Arena which does not feature first person hand models.

Set the MD3_EliteLoop metadata value to 1 to use Elite Force Single Player style looping values in animation.cfg. -1 for not looping and 0 for looping instead of Quake 3 style 0 for not looping and number of frames for looping. It is not supported by Quake 3. This is automatically detected when loading a player model if a looping value is -1.

Weapon Models

A typical MD3 weapon might be 5 GL units wide and 45 long. They usually would have no animations, although it should be possible to add animation by modifying the Quake 3 code. You can also add texture animations with shaders. Weapons are attached to the tag_weapon tag in the player model's upper model or first person hand model. Weapons typically have tag named tag_weapon at the model origin (0,0,0), however it is not used by the Quake 3 code. Some weapons have a tag named tag_flash where Quake 3 attaches the muzzle flash model (typically (weapon)_flash.md3 in the same directory). Some weapons have a tag named tag_barrel where Quake 3 attaches the barrel model (typically (weapon)_barrel.md3 in the same directory).

Hand Models

A hand model is used for positioning the first person weapon model. The model consists of only an animated tag_weapon tag and is not rendered by Quake 3.

Tags

Quake 3 uses tags to join models to each other. MM3D loads tags as points, so if you want to create a tag make a Point (more details about points). The point name should be whatever you want the name of the tag to be. The red axis of the tag is forward, the blue axis of the tag is up, and the green axis of the tag is left. For example you want the red side of that tag to face front for tag_weapon.

The MD3 orientation for tags is not the default orientation for MM3D points, so you must rotate any points you create into the correct orientation.

Animations

MD3 animations specify vertex positions for each vertex for each frame of each animation. This can be tedious. When creating a model from scratch it is usually easier to save the model in MM3D format and create skeletal animations. Then when you are ready to export to MD3, convert the skeletal animations to frame animations using the Animation Sets Window and save as an MD3.

Because of the enormous overhead of saving undo information for animations upon insertion and deletion of vertex and face primitives, you are not allowed to add or remove primitives from a model that has frame animations. You may, however, merge another existing model into the one you are working on. This is another reason why it is best to work with MM3D files and skeletal animations and only export MD3 files when necessary.

MM3D will save all frame (vertex, mesh deformation) animations when saving as MD3.

Paths

When an MD3 model is saved, path information is stored in the model. Quake3 uses a VFS (virtual file system), and you must tell Quake3 where your files are located in this VFS. For example a player model might be located in the Quake3 VFS at models/players/man/. So all the models and textures should probably be located in there and when you make a pk3 file (zip file really), it should contain that directory hierarchy.

We still need MM3D to save paths and filenames with models/players/man/. This is where the MD3_PATH metadata attribute comes in. You should set the MD3_PATH metadata attribute to models/players/man/. MD3 Filter will append all filenames that gets stored in the MD3 file to MD3_PATH. So your body.tga texture when saved would be written in the MD3 file as models/players/man/body.tga. When quake3 opens it that is where it will look in the VFS.

Note: The Quake 3 VFS does not start with a /.

Skins and Textures

The MD3 filter can load any image type as a texture if MM3D can use it. When looking for a texture file it ignores the extension and finds any loadable texture with the the right file name (regardless of extension). For example if the model says it should use a file called body.tga, MD3 Filter could use body.png if it exists.

MD3 filter looks for texture images and skin files in the same directory as the model regardless of the values for paths contained in the model.

In general the MD3 filter attempts to load skins in the following manner:

  • First it will look for .skin files with the following pattern. {modelName}_*.skin It will load all images inside those skin files. It will set the material to the image contained in {modelName}_default.skin.
  • If no .skins files are there it will use shaderName specified in the model to look for a texture file.
  • If that does not exist it will look for a valid texture whose filename matches {meshName}.*

When saving MD3 models it sets the shader name to the name of the texture that is assigned to the group. Also note that Quake3 by default only loads TGA and JPG files.

A skin file should be of the form indicated below.

mesh_name,MD3_PATH/textureFilename

and example upper_default.skin:

u_body,models/players/man/default_b.tga
u_cape,models/players/man/default_c.tga

Currently MD3 Filter will not load .shader files. These are files that could do complex OpenGL operations. You can still use shader files with your model inside Quake3 by creating the shader manually. Here is a example:

  • Set group texture to meshName.tga
  • Create a shader file called meshName.shader
  • Quake3 should see meshName.shader and use it because MM3D set it to look for meshName.* and Quake3 should take the shader file first.
  • Check your model in Quake3

MD3 Limits

The MD3 file format has several limits that you should consider when making a model for this format. These are outlined below. If your model has more that the MD3 limit, the file will not be saved correctly and you should get a error message.

  • Only faces and verticies in a group get saved.
  • The MD3_PATH+file name cannot be longer than 63 characters.  (Textures and model names)
  • The group name and point name cannot be longer than 63 characters.
  • Maximum of 1024 animation frames
  • Maximum of 16 Points (Quake 3 Tags)
  • Maximum of 32 Groups
  • Maximum of 256 Textures per Group
  • Maximum of 8192 Triangles per Group
  • Maximum of 4096 Verticies per Group
mm3d-master/doc/html/olh_quakemd3.page000066400000000000000000000000721324021725400201310ustar00rootroot00000000000000PAGE_TITLE=Quake MD3 Notes PAGE_CONTENT=Spherify Window

The Spherify Window is used to interactively morph the selected portion of a model into a spherical shape. It is made up of a slider and a text entry box for the spherify value.

The center of the spherify command is the center of the selected mesh. The sphere radius is the distance from the center of the mesh to the farthest selected vertex. As the spherify value increases, selected vertices are pushed away from the center until they are at the same distance from the center as the farthest vertex. A negative spherify value pulls internal selected vertices closer to the center of the selected mesh.

The spherify value ranges from -100 to 100 and starts at 0. A value of zero is the starting shape of the selected mesh. A higher value means the shape is more spherical, a lower value means the shape is less spherical. You can drag the slider left to decrease the value, or drag it right to increase the value. You can also change the value by typing a new value into the text box next to the slider.

Press Ok to keep your changes or press Cancel to ignore any changes.

mm3d-master/doc/html/olh_spherifywin.page000066400000000000000000000000751324021725400207710ustar00rootroot00000000000000PAGE_TITLE=Spherify Window PAGE_CONTENT=Texture Coordinate Details

Overview

Texture Coordinates define how a 2D image texture map is applied to the faces of a group. Each vertex of each triangle has its own set of texture coordinates. If two triangles share a vertex, each triangle may have different texture coordinates for the same vertex.

Creating Texture Coordinates

Texture coordinates are created implicitly when a triangle is created. The default coordinates are not very sensible or useful.

Other Texture Coordinate Details

To change the way the texture is mapped onto a group of faces you will need to use the Texture Coordinates Window. Typically when using the Texture Coordinate Window you will start by selecting the "Group" map scheme. This method of setting up starting texture coordinates can be somewhat limiting. Sometimes using a Texture Projection gives you a better starting point for texture coordinate assignment.

After using a group map scheme or texture projection to get the texture coordinates in roughly the place you want them, you can use the viewport in the Texture Coordinates Window to select triangle vertices and move the coordinates. The viewport in the texture coordinates window follows most of the same conventions as the model viewports.

See Also

mm3d-master/doc/html/olh_texturecoorddetails.page000066400000000000000000000001201324021725400225060ustar00rootroot00000000000000PAGE_TITLE=Texture Coordinate Details PAGE_CONTENT=Texture Coordinates Window

The Texture Coordinates Window is used to change how a texture is applied to the faces of the model. It applies each vertex of a face to a point on a texture. The texture is then stretched between each vertex on the face to create the final texture appearance on the model. To change the texture coordinates, select faces you wish to modify and select Edit Texture Coordinates in the Main Window's Groups menu.

The Texture Coordinates Window contains four major elements:

  • Texture Frame - Shows the texture image with vertices and faces drawn over it.
  • Mouse Tool Buttons - Determine what happens when you use the mouse on the Texture Frame.
  • Scale Options Frame - Gives some control over how the scaling operation works.
  • Map Scheme Buttons - Change the initial coordinate mapping scheme for the selected faces.

The Texture Frame viewport shows the texture used by the selected faces. Faces and vertices are drawn over the texture to show where each face's vertices are applied to the texture. Vertices can be selected, unselected and moved using the left and right mouse buttons. The exact operation performed by the mouse depends on which Mouse Tool is selected.

The Texture Frame is very similar to the model viewports. You can pan around the Texture Frame by using the arrow buttons inside the frame window, or by middle-click dragging. You can zoom in or out by using the Zoom Buttons or by using the mouse scroll wheel.

The Rotate CCW and Rotate CW buttons rotate the selected texture coordinate vertices 90 degrees counter-clockwise and clockwise.

The V Flip and H Flip buttons will perform a vertical or horizontal flip on the selected texture coordinate vertices.

The Mouse Tool buttons determine what the mouse buttons do when used in the Texture Frame. Most tools operate in a similar fashion as the tools in the view window (an exception is that you may only select vertices).

  • The Select button allows you to select vertices with the left mouse button and unselect vertices with the right mouse button. You can hold the shift key to make your selection cumulative.
  • The Move button allows you to move selected vertices.
  • The Rotate button allows you to rotate selected vertices.
  • The Scale button allows you to scale the distance between selected vertices. Using the Scale Options frame you can control whether you scale from the center of the selected vertices or the far corner and whether or not the 2D aspect ratio of the selection is preserved during the scaling.

The Map Scheme buttons are used to set the initial coordinates for the faces. The Triangle mapping uses the same coordinates for all three vertices of each face. The Quad mapping uses three coordinates from two triangles for alternating faces. The Group mapping projects the selected faces from a specified direction onto the texture image. Each vertex has its own coordinate and may be moved independently.

When you click on the Group radio button you will be prompted to chose one of six directions. Misfit will take the selected faces as they appear in the orthographic view of your chosing, scale them to the size of the texture image, and project them onto the texture image.

Texture Projections are a more powerful alternative to the group mapping scheme.

The Reset Coordinates button is used to reapply the current map scheme to the texture coordinates. If you click this button while using the Group mapping scheme you will be asked to pick a direction again.

The next time you open the Texture Coordinates Window with the same faces selected, it will show the vertex coordinates that you set previously.

Press Close to close the Window.

See Also

mm3d-master/doc/html/olh_texturecoordwin.page000066400000000000000000000001141324021725400216610ustar00rootroot00000000000000PAGE_TITLE=Texture Coordinates Window PAGE_CONTENT=Materials Window

The Materials Window is used to add or remove model materials (aka, textures) You may also modify the reflective properties of the material. Select Edit Materials from the Main Window's Matererials menu.

The combo box at the top of the window contains the names of all materials associated with this model. You can select a material name and use the lighting property sliders to adjust the reflective properties (Ambient, Diffuse, Specular, Emissive, and Shininess) of the material.

  • Ambient - Light reflected from no particular direction.
  • Diffuse - Light reflected from the primary light source.
  • Specular - Light reflected which brings out highlights in the material.
  • Emmisive - Light emmited from the material's surface.

Each lighting color value ranges from -1.0 to 1.0. You can drag the slider left to decrease a color's value, or drag it right to increase a color's value. You can also change a value by typing a new value into the text box next to the slider.

The material preview can be a flat texture image or a 3D preview of the texture mapped onto a cube. Use the material preview combo box to switch between preview modes.

To add a new material click the New Material and enter a name. To add a 2D texture image to the material, click the Set Texture button and select a file. The file dialog box will show you which image file formats are supported. You should select an image with dimensions that are a power of 2 (ie, 32x32, 128x256, etc...). Other sizes should work with Misfit, but may not work with other rendering engines.

To remove a texture from the current material click the X button next to Set Texture.

To remove a material from the model, select the material name in the combo box and click the Delete button (this only removes the material from the model, the actual file on disk is not modified in any way).

To rename a material click the Rename button. This may be useful if you want the material name to match a group name, or if you have two materials with the same image but different lighting values. Names do not need to be unique (though duplicate names may be confusing for other people using the model).

You can change the texture wrapping behavior by changing the value of the the Wrap/Clamp combo boxes. Wrap will cause the texture to wrap for texture coordinates that are outside of the 0.0 to 1.0 range. Clamp will cause the renderer to extend the edge of the texture in the desired direction. The X and Y clamp values can be changed independently.

Press Ok to keep your changes or press Cancel to ignore any changes.

See Also

mm3d-master/doc/html/olh_texturewin.page000066400000000000000000000000751324021725400206400ustar00rootroot00000000000000PAGE_TITLE=Materials Window PAGE_CONTENT= Quick Tips

This page describes some short tips that can help you use Misfit Model 3D more effectively.

General Modeling Tips

  • Properties Panel -- Some parts of a 3D model will have modifiable properties that can be changed through dialog boxes or the Properties Panel. The Properties Panel is a context-sensitive dockable window that displays modifiable properties for the selected portion of the 3D model. Using the Properties Panel may be more convenient than using tools, commands, or dialog boxes to accomplish some tasks. Select "View | Show Properties" to use the Properties Panel.
  • Background Images -- When creating a model, it is sometimes helpful to have a 2D image for reference to help with getting the shape or scale of some object correct. You can project a 2D image into any viewport using Model | Select Background Image.
  • Snap to Grid/Vertex -- Use "Tools | Snap To | Grid" and "Tools | Snap To | Vertex" to help align the current tool with the grid lines and existing vertices.
  • Drag Vertex -- Use Drag vertex on edge to move a vertex along one of the triangle edges it is connected to. The tool will attempt to follow the edge that is closest to the mouse.
  • Edge Turn -- If two triangle form a concave angle when you want a convex angle (or vice-versa), use Edge turn. See the link for an example of when this is useful.
  • Extrude -- Use "Extrude" to take a set of faces and extend it out from the object it is connected to. There is a geometry command version and a tool version.
  • Shift Key -- Some tools modify their behavior if you hold the shift key while using them. For example, the move tool will operate only in one dimension and the rotate tool will rotate in 15 degree increments. Often these behaviors are noted in the status bar when you change tools. Any special behavior of the shift key for a tool will be described in the tool documentation
  • Face Out -- Triangles/faces only reflect light off of one side. If the dark side of a triangle is facing out toward the camera, you need to invert the normal of the triangle to reverse the direction it faces. If an enclosed 3D shape has some triangles facing in and some facing out, you can select the entire shape and use Geometry | Normals | Normals face out to correct any faces that are wrong. This can be easier than manually selecting faces and inverting them. Note that this only works if the faces are part of a complete, enclosed 3D shape.
  • Snap Together -- You can use Snap Together to make nearby vertices align themselves. Optionally you can have them weld into a single vertex. This operation can work on all selected vertcies, or pairs of nearby vertices.

Viewports

  • Swith to Orthographic -- You may only use selection and modification tools in orthographic projections. If you see something in a 3D perspective projection that looks wrong and you are not sure which faces or vertices to select from an orthographic viewport, you can switch the perspective viewport into an orthographic viewport from the same angle by pressing the the left quote/backtick key (`).
  • Rotate 180 -- The Backslash key (\) will rotate the viewport 180 degrees so that you are looking at the opposite side of the object in your viewport.
  • Pan -- Click and drag the middle mouse button in a viewport to pan. You can also use the arrow keys to pan any viewport that is highlighted with mouse focus.
  • Zoom -- Use the vertical scroll wheel or the plus/minus keys to zoom in or out.
  • Rotate -- Use Ctrl + scroll wheel or Ctrl + plus/minus keys to rotate the viewport around the viewing axis.
  • Save/Restore View Angle -- Pressing Ctrl + <Number Key 1-9> will save the current rotation and zoom level of the highlighted viewport. Pressing the number key alone will recall the saved position and rotation. Pressing 0 will center the viewport on the origin.
  • Frame Selected/All -- Use "View | Frame Selected" or "View | Frame All" to and zoom your viewport on the object of interest (note that this changes all viewports).

Texturing

  • Texture Groups -- To apply textures to geometry, the faces/triangles must be part of a group. The texture is then applied to the group.
  • Texture Projections -- Texture unwrapping is not supported, but using cylinder and sphere texture projections in addition to paint texture may give you a good starting point for applying textures.
  • Reload Textures -- If you are modifying your textures in a paint program, you can reload the model textures without restarting by selecting the "Reload Textures" option in the Materials menu.

Animations

  • Prefer Skeletal Animations -- Skeletal animations tend to be easier to work with than frame animations. For model formats that require frame (mesh deformation) animations--such as the quake formats--it is best to create skeletal animations and then convert those animations to frame animations before exporting to the desired format.
  • Setting Keyframes -- Keyframes are automatically created when you move or rotate a joint. If you want to create a keyframe without rotating or moving, use the "Set Rotation/Translation Keyframe" options.
  • Prefer Rotation Keyframes -- Beginners sometimes try to move the joints instead of rotating. Use rotation on the bone joints to animate your model instead of translation (think about how you move your own arms and legs).
  • Set starting and ending keyframes -- It is a good idea to set a keyframe in the first and last frame of an animation for every joint that will be animated during the animation. This will give you more predictable results regardless of whether the animation is looping or not.

Alpha Blending

  • Backfacing Polygons -- When working with transparent textures on a model, keep in mind that back-facing polygons are often not rendered by various rendering engines. Typically you will want to render back-facing polygons when you are modeling. However you can disable back-facing polygons from the View menu if you want to see what your model will look like.
  • Offset Co-planar Triangles -- Since triangles only render facing one direction, transparent triangles are sometimes doubled so that they are rendered properly when viewed from both directions. If these triangles are exactly co-planar you may see rendering artifacts that cause part of the triangle that should be rendered to be obscured. To prevent this, put a slight gap between the co-planar triangles.

Importing and Exporting

  • Work in MM3D Format -- Some supported file formats do not mix well with the way MM3D stores data internally. When working with 3D models on a regular basis it is often a good idea to save in MM3D format and then use "File | Export" to save in your desired format when you have something completed. There are many more exportable formats than save formats.
  • Import Animations -- You can use "Model | Import Animations" to load animations from another model with an identical skeletal structure. The skeleton will be checked to make sure that the parent/child joint relationships are correct. The position and rotation of the joints will not be checked, but if they are not identical the results of the import will probably not be what you expect.
  • Model Merge -- You can use "Model | Merge" to import another model into the current one. There are options for scaling and rotating as well as how to deal with animations. The merge feature can be useful if you have frame animations in your model, since adding and deleting geometry in general is not allowed in that case.
  • Format-Specific Notes -- Some model export formats have special considerations that you must keep in mind when you are working with them. See the links below for details.

Advanced

  • Boolean Operations -- Use Boolean operations to modify one 3D object based on the shape of another 3D object. Boolean operations can combine two shapes into one, subtract the volume of one shape from another, or find the common volume between two shapes. After using a boolean operation you may want to use Simplify Mesh to combine some newly created faces.
  • Custom Keyboard Shortcuts -- It is possible to customize most menu shortcuts. There is no graphical user interface to do this, but you can edit a file called keycfg.in in the $(HOME)/.mm3d subdirectory (on Win32 this is userhome in the Misfit Model 3D Program Files directory). Simply specify the name of the function you want to bind and then the key combination you want to bind it to. See keycfg.out in the same directory for the current bindings. Anything you do not specify in your keycfg.in will use the default setting.
mm3d-master/doc/html/olh_tips.page000066400000000000000000000000611324021725400173740ustar00rootroot00000000000000PAGE_TITLE=Quick Tips PAGE_CONTENT=Tools

General Usage

Tools


Using the toolbar

The Toolbar has a set of tool buttons. The tool buttons represent tools that allow you to manipulate a model interactively. For example, you can select the "Create Cube" tool and then click and drag the mouse in a viewport on the Main Window to create a cube.

There are two types of tools in the toolbar: Creation tools and manipulation tools. Creation tools create new vertices, faces, and joints interactively in various shapes such as cubes and spheres. Manipulation tools allow you to interactively change faces, vertices, and joints which already exist. Manipulation tools include moving, scaling, and rotation tools. Typically manipulation tools only operate on vertices, faces, or joints which have been selected with the "Select" tool.

It is important to note that faces often share vertices. Unselected faces may be modified by changes to vertices which are also part of a selected face. To disconnect faces from each other so that they do not share vertices, see the Unweld vertices command.

Some tools have additional options, which appear in an a separate toolbar. For example, the sphere tool has an option that specifies how many triangles the sphere will be composed of.


Snap to Grid/Vertex

The tools menu contains a "Snap To" submenu. In this submenu there are two options: "Snap to Grid" and "Snap to Vertex". The former will cause objects dragged by the mouse to align with the nearest grid line when it comes close enough. The latter will cause the objects to align with the nearest vertex.

Tools

Select

Overview

Select vertex tool icon Select face tool icon Select connected tool icon Select group tool icon Select bone joint tool icon Select point tool icon Select projection tool icon
There are seven Select tools that allow you to select vertices, faces, connected meshes, groups, bone joints, points, and texture projections. Each behaves in a similar manner as described below.

Mouse operations

Click and drag in a canvas viewport with the left mouse button. This will create a bouding box. When you release the mouse button all objects of the desired type (vertices, faces, groups, or joints) that are within the bouding box will be selected. In the case of faces or groups, the entire face or group does not need to be within the bouding box. If any portion of the object is within the bouding box it will be selected.

Each time you press the left mouse button you begin a new selection. If you want the selection to be cumulative, you may hold a shift key down to prevent the tool from unselecting vertices. Using the shift key in this way you may select multiple objects by repeatedly using the left mouse button.

The right mouse button is used to unselect objects. You do not need to hold the shift key down to prevent clearing all of the current selection. This is implicit when using the right mouse button.

The select faces tool has an option to select back-facing faces. If checked, any faces in the selected region will be selected (this is the default behavior). If unchecked, only faces that are facing the camera in the selected region will be selected.

Animation mode

The select tools operate the same way in animation mode as they do in model edit mode; however, some animation types do not allow you to select some objects. For example, in skeletal animation mode you can only manipulate bone joints.

Keyboard shortcuts

  • V - Select Vertices
  • F - Select Faces
  • G - Select Groups
  • C - Select Connected
  • B - Select Bone Joints
  • T - Select Points

Move

Overview

Move tool icon
The Move tool moves selected vertices and faces.

Mouse operations

Press and hold the left or right mouse button in a canvas view to begin a move operation. Drag the mouse with a button down to move selected vertices or faces in a canvas view.

You can force the move tool to only move in one dimension by holding the shift key. The first dimension the tool detects movement on will be the only dimension you can move the selected primitives in.

Animation mode

In animation mode the move tool moves vertices or bone joints. The move tool may have no effect on certain types of animations. In skeletal animations, moving a bone joint will set a translation keyframe for the current frame of the current animation. For frame animations, moving vertices will set the vertex position for the current frame of the current animation.

Keyboard shortcuts

  • M - Move Tool

Rotate

Overview

Rotate tool icon
The Rotate tool rotates selected vertices and faces around a point.

Mouse operations

Press and hold the left mouse button in a canvas view to begin a rotate operation. Drag the mouse around the rotation point (default rotation point is the center of the seleced object, but this can be changed with the right mouse button).

Hold the shift button to rotate selected vertices in 15 degree increments. This can be useful if you want to rotate something by an exact amount (like 15, 30, 45, 90, or 180 degrees.

The right mouse button sets the rotation point in the canvas view. The rotation point is indicated by a green crosshair.

Animation mode

In animation mode the rotate tool rotates vertices for frame animations and sets rotation keyframes for bone joints in skeletal animations. The rotation of vertices is identical to the operation in model edit mode. The rotation of bone joints is different from model edit mode in that the rotation is always centered on the bone joint.

Keyboard shortcuts

  • R - Rotate

Scale

Overview

Scale tool icon
Scale selected vertices and faces.

Mouse operations

Press and hold a mouse button to begin a scale operation.

You can specify whether to scale from the far corner of the selected mesh or the center of the selected mesh by changing the Point combo box in the toolbar. By default the center point is used.

The amount of scaling is based on the position of the mouse relative to the scaling point, and the position of each selected vertex (vertices farther from the scaling point will scale more than vertices closer to the scaling point).

You can force the scale tool to preserve the aspect ratio of the scaled object in 2 or 3 dimensions using the combo box in the toolbar. By default the aspect ratio is not preserved.

You can force the scale tool to only scale in one dimension by holding the shift key. The first dimension the tool detects movement on will be the only one scaled. The shift key is ignored if you are preserving the aspect ratio through the combo box (input will only be counted on in one dimension, but 2 or 3 will be scaled by that input).

Animation mode

In animation mode the scale tool scales vertices for frame animations. It has no effect on skeletal animations.

Keyboard shortcuts

  • None

Shear

Overview

Shear tool icon
Shear selected vertices and faces.

Mouse operations

Press and hold a mouse button to begin a shear operation. The shear tool will find the bounds of the selected vertices. The nearest edge of the bounding region will be dragged in the direction of mouse movements. For example if the nearest bounding edge is the top edge, the top edge will move left or right while the bottom edge will remain stationary.

Horizontal edges move left or right. Vertical edges move up or down. Vertices between the moving edge and anchored edge will move proportionally based on their relative position between the two edges.

Animation mode

In animation mode the shear tool shears vertices for frame animations. It has no effect on skeletal animations.

Keyboard shortcuts

  • None

Extrude

Extrude tool icon
Extrude selected faces. This works like the extrude tool except that instead of entering a numeric offset for the location of the extruded faces, you drag the faces to the desired location with the mouse.

Mouse operations

Press and hold a mouse button to begin an extrude operation. The faces you select will move with the mouse. New faces will be created to connect the moving faces to the rest of the object. If you release the mouse button and press and hold again, it will start a new extrude operation.

Animation mode

This tool works like a create tool and has no effect in animation mode.

Keyboard shortcuts

  • None

Drag Vertex on Edge

Overview

Drag vertex tool icon
Drag Vertex on Edge of a triangle toward connected vertices.

Mouse operations

Press and hold a mouse button to begin a drag operation. As you move the vertex it will follow the closest edge of a triangle that the vertex belongs to.

Before

After

Animation mode

In animation mode the drag vertex tool moves vertices for frame animations. It has no effect on skeletal animations.

Keyboard shortcuts

  • None

Attract Near

Overview

Attract near tool icon
Attract Near translates selected vertices. Vertices closer to the mouse are affected more by the translation than far vertices.

Mouse operations

Press and hold a mouse button to begin an attract near operation. Drag the mouse to move the selected vertices. The nearest vertices will move the most. The farthest vertices will not move at all.

Animation mode

In animation mode the attract near tool moves vertices for frame animations. It has no effect on skeletal animations.

Keyboard shortcuts

  • None

Attract Far

Overview

Attract far tool icon
Attract Far translates selected vertices. Vertices farther from the mouse are affected more by the translation than near vertices.

Mouse operations

Press and hold a mouse button to begin an attract far operation. Drag the mouse to move the selected vertices. The farthest vertices will move the most. The nearest vertices will not move at all.

Animation mode

In animation mode the attract near tool moves vertices for frame animations. It has no effect on skeletal animations.

Keyboard shortcuts

  • None

Move Background Image

Overview

Move background image tool icon
The Move Background Image tool moves the center point of a canvas background image.

To set a background image for a viewport, use the Select Background Image Window.

Mouse operations

Press and hold a mouse button to drag the image to the desired position.

Keyboard shortcuts

  • None

Scale Background Image

Overview

Scale background image tool icon
The Scale Background Image tool increases or decreases the size of the canvas background image.

Mouse operations

Press and hold a mouse button to scale the image size up or down. Moving closer to the center will make the image smaller. Moving away from the center will make the image larger.

It is not possible to scale the X and Y dimensions independently.

To set a background image for a viewport, use the Select Background Image Window.

Keyboard shortcuts

  • None

Create Rectangle

Overview

Create rectangle tool icon
The Create Rectangle tool creates two triangular faces that form a rectangle.

Mouse operations

Press and hold a mouse button to begin creating a rectangle. The first corner of the rectangle will be located at the point of the mouse button press. Move the mouse to the location of the far corner and release the mouse button to finish creating the rectangle.

Animation mode

Create tools have no effect in animation mode.

Create Vertex

Overview

Create vertex tool icon
The Create Vertex tool creates a vertex that is not connected to any triangles.

Normally vertices that are created when triangles are created will also be deleted when triangles are deleted. A vertex created with the Create Vertex tool is a "Free Vertex". You can create a triangle connected to this vertex then delete the triangle later and the vertex will still be present. A "Free Vertex" will only be deleted if it is selected explicitly and deleted.

Mouse operations

Press a mouse button to create a vertex. If you hold the button down you can move the new vertex until the button is released.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Cube

Overview

Create cube tool icon
The Create Cube tool creates a set of faces in the shape of a cube.

When you select the create cube tool the cube tool bar will appear. You can use the cube tool bar to force the new cube to be cube shaped (the same width, height, and depth). You can also increase the number of faces that make up the cube by changing the value of segments. The segment value is N for an N by N by N cube. So a segment value of 3 would give you nine sets of squares (3x3) on each cube face (9 squares, 18 faces).

Mouse operations

Press and hold a mouse button to begin creating a cube. The first corner of the cube will be located at the point of the mouse button press. Move the mouse to the location of the far corner and release the mouse button to finish creating the cube.

The cube will be as deep as its narrowest side.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Ellipsoid

Overview

Create ellipsoid tool icon
The Create Ellipsoid tool creates a set of faces in the shape of an ellipsoid. The depth dimension of the tool will be identical to the shorter of the two radii (an ellipse is cigar-shaped, not plate-shaped).

When you select the ellipsoid tool the ellipsoid tool bar will appear. You can use the ellipsoid tool bar to increase the smoothness of the ellipsoid or make the ellipse a sphere (forcing the the radii to be the same in all three dimensions).

Mouse operations

Press and hold a mouse button to begin creating an ellipsoid. The ellipsoid will be drawn within the space you drag the mouse over, or with the center at the original click point, depending on the value of the From center check box in the tool bar. Release the mouse button to finish creating the ellipsoid.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Cylinder

Overview

Create cylinder tool icon
The Create Cylinder tool creates a set of faces in the shape of a cylinder. The cylinder is always drawn "horizontally" in the canvas view. The "width" is the length of the cylinder and the "height" is the diameter of the cylinder. Cylinders may be solid or hollow and may taper at one end.

When you select the cylinder tool the cylinder tool bar will appear. You can use the cylinder tool bar to increase the the number of segments (lengthwise) of the cylinder by setting the segments spin box. You can increase the the number of sides (around the cylinder) of the cylinder by setting the sides spin box. You can make a cylinder hollow by using the width spin box. The width is how think the cylinder is (as a percent of the radius). 100 is solid and 0 is an extremely thin cylinder. The scale is the size of one end of the cylinder relative to the other as a percentage of the total diameter. 100 is a cylinder, 0 is a cone with one pointed end.

Mouse operations

Press and hold a mouse button to begin creating a cylinder. The diameter of the cylinder will be the "height" (vertical distance) in the current canvas view. If the cylinder is cone-shaped, the smaller end will be where the drag began. Cylinders are always "horizontal" in the current viewport. You can use the rotate tool to change the orientation of a cylinder that has been created (holding down shift during rotation will allow you to rotate in 15 degree increments).

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Torus

Overview

Create torus tool icon
The Create Torus tool creates a set of faces in the shape of a torus. The torus is always drawn with the "hole" visible in the canvas view where the torus was created. You can increase the polygon count of the torus by changing the "smooth" value.

When you select the torus tool the torus tool bar will appear.

The width is width of the cylindrical portion wrapped around the center. 50 means the cylinder spans from the far outside of the torus to halfway to the middle of the torus. 100 means the cylinder spans all the way to the center of the torus. 199 means the torus will be almost spherical.

You can check the circle checkbox to force the torus to be circular.

Mouse operations

Press and hold a mouse button to begin creating a torus.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Polygon

Overview

Create polygon tool icon
The Create Polygon tool creates a triangle strip or fan. Each left click will create a new vertex for the polygon.

When you select the polygon tool the polygon tool bar will appear.

If the fan checkbox is checked the polygon will be a triangle fan. If the checkbox is unchecked, the polygon will be a triangle strip.

You can check the circle checkbox to force the torus to be circular.

Mouse operations

Press the left mouse button to create each vertex of the polygon. Press the right mouse button to invert the normals of the most recently created polygon.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Bone Joint

Overview

Create bone joint tool icon
The Create Bone Joint tool creates a bone joint connected to the nearest bone joint.

Mouse operations

Press a mouse button to create a bone joint. Hold the button down to move the joint where you want it. If there are no other joints the first joint you create will be a root joint. If there are other joints, the new joint will be connected to the closest existing joint (the existing joint will be the "parent" of the new joint).

The closest joint is the closest joint in the two dimensions of the orthographic canvas view you are creating the bone joint in. The third dimension (the depth) is not included in the distance calculation.

If you want the joint to be connected to a joint other than the closest one to the place where the joint will be positioned, create it near the parent joint and drag it to its target location.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Point

Overview

Create point tool icon
The Create Point tool creates a point. Points have a position and a direction. Points do not have a specific purpose for MM3D. They can be used as bolt points or other custom-purpose tags for model exporters or game engines. For example, the MD3 filter looks for specially named points to act as MD3 "tags".

You can use the rotate tool to rotate a point into a new direction, or explicitly set the rotation using the Rotation Properties Panel.

Points can be assigned to bone joints in the same manner as vertices.

Mouse operations

Press a mouse button to create a point. Hold the button down to move the point where you want it.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

Create Texture Projection

Overview

Create texture projection tool icon
The Create Texture Projection tool creates an object to project a texture onto faces as a sphere or cylinder. Texture Projections have a position and a rotation. Texture projections do not have a texture associated with them. The texture applied to faces is the texture assigned to the group to which the faces belong (in theory you could use the same texture projection to map two different textures onto two different sets of polygons).

You can change the type of projection to create by selecting the type from the Type combo box. You can also change the type of a projection after creating it using either the Texture Projections Window or the Projection Properties Panel.

Any faces that are selected when you create the projection will automatically be assigned to the projection.

Mouse operations

Press a mouse button to create a texture projection. Hold the button down to scale and rotate the projection to the size and orientation that you desire.

Animation mode

Create tools have no effect in animation mode.

Keyboard shortcuts

  • None

mm3d-master/doc/html/olh_tools.page000066400000000000000000000000561324021725400175610ustar00rootroot00000000000000PAGE_TITLE=Tools PAGE_CONTENT=Transform Model Window Transform Model Window allows you to apply a transformation Matrix to the model. There are tabs in the window for translation, rotation, and scaling, as well as a tab for a user-defined matrix. In some cases the Matrix you want to apply may not be undo-able. If this is the case, the window will warn you before performing the transformation.

Translate

In the Translate tab you can enter the X, Y, and Z components of the translation. Press the Translate button to perform the translation.

Rotate

In the Rotate tab you can enter a rotation as euler angles (rotation on the X axis, Y axis, or Z axis in degrees) or as a quaternion (a user-defined axis of rotation and an angle in degrees). Press the Rotate button to perform the rotation (you must press the button in the same frame as the rotation numbers that you entered).

Scale

In the Scale tab you can enter the X, Y, and Z components of the scale. Press the Scale button to perform the scale.

Matrix

In the Matrix tab you can enter any transformation matrix you want. For reference, the translation component is in the bottom row (as opposed to the rightmost column). Press the Apply Matrix button to apply the matrix to the model.

Press Close to close the window.

mm3d-master/doc/html/olh_transformwin.page000066400000000000000000000001051324021725400211450ustar00rootroot00000000000000PAGE_TITLE=Transform Model Window PAGE_CONTENT=MM3D Tutorial - Modeling Geometry


Getting Started

Introduction

This tutorial will demonstrate how to use Misfit Model 3D. The example model will be a humanoid character with texture maps and animations. The model will be aimed at an eventual MD3 export, because this demonstrates nearly all of Misfit Model 3D's capabilities.

Note that I am not an artist--neither 2D nor 3D, so my 3D model creation skills are somewhat limited. This fact should be obvious by the time you see the finished model. Also note that I am taking some short-cuts in the interest of producing this tutorial more quickly. There are several places where spending more time on detail would provide better results; but my goal was to finish this document rather than create a refined example of 3D art.

Meta Data

The first thing I'm going to do is open up the Model Meta Data Window from the Model menu. The Meta Data Window allows you to enter some non-rendered information about the model. In this case I'm just going to note my own name in a copyright string by clicking "New", then double-clicking on the row to edit the key and value.

In this instance the meta data is entirely optional. You can enter any sort of information you want in this window, or leave it completely empty. In some cases, meta data is used by import or export filters to track format-specific data that Misfit Model 3D's model class doesn't understand (for example, skin path information in MD3).

Background Images

Next I'm going to add a background image to my forward-facing viewport to aid in constructing the humanoid model. In this case I'll be using DaVinci's "Proportions". Often you'll want to use a reference object with images from multiple angles so you can get a better sense of width and depth.

The model is not intended to look exactly like DaVinci's work, it's just a rough guide.

The background image window has a tab for each viewport direction. In my case, I'm just selecting the Forward tab and selecting an image file.


Torso -- Creating Basic Shapes

Pick a Starting Shape

When creating a 3D object, you will usually start with one of the basic creation tools (cube, ellipse, cylinder, or torus). From there you can move vertices around to get the basic shape right and split edges or extrude to add detail.

For our humanoid model, a cylinder is roughly the right shape for all the large geometry components. Expect to see many of those.

Reshaping Geometry

I am starting with the torso, so I will create a cylinder for that. Cylinders are always created horizontally with respect to the viewport in which they are created. So after creating this cylinder I need to rotate it vertically. If you hold the shift key down while rotating, the rotate tool will rotate in 15 degree increments. This makes it very easy to get the cylinder perfectly vertical.

Now I want to use the Front viewport background image as a reference to relocate vertices. The selection tools allow you to select portions of the model. There are selection tools for vertices, faces, material groups, connected meshes, etc. You start a selection operation with the mouse button, and use the bounding box to select the region that contains the geometry you want to select.

The left mouse button selects geometry, the right mouse button unselects. If you press the left mouse button alone, all selected portions of the model will automatically be unselected. If you hold the shift button the current selection will remain selected. The right mouse button never clears the current selection.

I use the Select Vertices tool to select the vertices for the upper body and use the Scale Tool to resize that section all at once. Then I select vertices down the sides and move them to match the outline of the image.

Next I use the side viewport to adjust the vertices in the Z (depth) axis, which isn't possible from the Front view. In this case the X (width) axis and Y (height) axis are correct. So I want to be careful to only move the vertices left or right in the Side viewport. If I hold down the shift key while using the Move Tool, the move tool will only move on one axis--the first axis it detects motion on.


Torso -- Detail Adjustments

Edge Turn

Of course vertices are not the only things to be concerned with when shaping the geometry. The faces themselves need attention too. Note the highlighted faces near the base of the torso in the image. The edge where the faces meet forms a concave angle on the outside of the geometry. A convex angle would look more correct. We can fix this with an Edge Turn. This rotates the edge from the two shared vertices of a face to the two opposite vertices.

If you do any significant work in a 3D model editor, you will make regular use of the Edge Turn feature. If you are just starting out with 3D modelling and the faces look wrong even though all the vertices seem to be in the right place, it is probably because you need some edge turns. Occasionally you'll need a sequence of edge turns. Note that edge turns do not preserve texture coordinates, so you'll want to make sure your geometry is mostly where you want it to be before you starting applying a texture map to it.

Edge Divide

The basic torso shape is in place, but it looks a bit angular on the sides. To fix this I'm going to split faces by doing a series of Edge Divide operations. If you have two vertices selected, and do an Edge Divide, it will add a vertex between the two vertices and split any triangles that use that edge into two triangles.

I mentioned above that you select the vertices of the edge to split. Selecting the edge would be more intuitive, but edges are not first-class objects in Misfit Model 3D, so there isn't a way to select the edge. However, you can select a face that uses the edge and then unselect the odd vertex that isn't on the edge you want to split (use the shift key with the select tool to unselect selected geometry).

Snap, Weld, and Hide

I'm splitting some edges, but I'm also welding some vertices back together. Welding vertices causes two or more vertices selected vertices that are near each other to become one vertex. This may cause some triangles to be removed implicitly (if a triangle has an edge with two vertices that are welded, the triangle becomes invisible and is unecessary). To get the vertices lined up I'm using the Snap to Vertex feature. Alternatively you could use the Snap Together command. The Snap Together command has welding and non-welding versions.

While I am working on one side of the model, faces from the other side are visible in the same viewport and are distracting, so I use the Hide command to make that portion of the model invisible. While hidden, the geometry still exists but it is not drawn and it will not be modified except under some specific circumstances. Some hidden faces may share vertices with unhidden faces. If you move those shared vertices the hidden faces will be modified.

Boolean Operations and Flipping

Now that one side looks good I want to make the other side match it. I could repeat all the work I did on the opposite side, but I'd rather not go through that effort. What would be easier would be to cut the torso in half, duplicate the side that I've finished, and then mirror it so that both sides are identical.

Here I use the Boolean Operation panel to cut the torso in half (read more about boolean operations if the following doesn't make sense). I will set the torso as Object A and subtract a cube from the torso. I use the Simlify Mesh command to remove faces that don't add detail.

Then I remove the faces that will be inside the torso since they won't be visible. Finally I Duplicate the half of the torso and Flip it. I select the vertices down the middle and use the Weld command to join the torso together again. Note that weld only welds vertices that are extremely close, so I can weld all the verticies in one operation.

If you're thinking that this use of Boolean Operations is a bit contrived, I agree. Boolean operations can work with much more complex objects than what I have shown here, but this works well as a basic example.


Torso and Legs -- Combining Shapes

I'm ready to start working on the legs. Before I do that I want to adjust the depth of the torso. Assuming that the depth of the torso is about the same as the width of the upper leg, I'll use the same background image in the side view as the front view, then I'll scale the depth of the torso until it looks about right.

For the legs, we'll start with the left leg and plan to duplicate it. First I create a cylinder, this time with more sides since I ended up increasing that with the torso manually. Again, the tool creates the cylinder horizontally, so I shift-rotate it to vertical. Then I'll scale it to be roughly the right proportions for the leg reference.

Now I connect the leg to the torso. I remove the faces on the bottom of the torso and the top of the leg where the two will connect. I use snap to vertex with the move tool to connect the vertices. Then I use weld to fuse the two meshes into one.

I need to do an edge turn to make the angles look right. Finding the right faces to select in the orthographic side and front projections can be tricky. So instead, I flip the perspective view into an orthographic projection and use that projection to select the faces. Then I flip back to perspective to make sure the right faces are selected. Finally I do the edge turn.

Now I move the leg vertices in the side view to match the leg in the background image. Note that the reference image has the leg twisted to one side, so this should be pretty close to the expected final results. The process for using the background image as a reference for the vertices is the same as for the torso.

Now I need to add a foot. Rather than creating a separate piece of geometry and welding it on, I will extrude existing faces on the leg into a foot. The extrude feature is available as an interactive Extrude Tool and an Extrude Geometry Command. I will be using the tool version here.

First I extrude the bottom faces to make segments for the ankle and heel. Before extruding the foot itself I move some toe-side leg vertices up to the ankle and use Snap Nearest and Weld. Then I extrude the front faces on the ankle/heel to make the foot. Finally I move the foot vertices around a bit to make the foot look more... foot-like.

Zooming out a bit, the leg looks somewhat curvy. I adjust the leg vertices to take some of the curve out.

Now that the leg is in pretty good shape, I want to duplicate it for the right side. This is just a simple matter of select, duplicate and flip. Because the torso is symmetrical (and I didn't move the torso vertices to connect the leg) all I need to do to fuse the meshes together is select the vertices on the seam and weld them together.

Now that I have two legs, the model looks pigeon-toed. So I'll adjust that now.

mm3d-master/doc/html/olh_tutorial_index.htm000066400000000000000000000002341324021725400213250ustar00rootroot00000000000000

MM3D Tutorial - Table of Contents

Sorry, I still haven't written this tutorial.

mm3d-master/doc/html/olh_tutorial_index.page000066400000000000000000000001061324021725400214470ustar00rootroot00000000000000PAGE_TITLE=MM3D Tutorial - Index PAGE_CONTENT=Vertex Details

Overview

A vertex is a geometric point. A model triangle (or face) is defined by the three vertices that are connected to form the triangle. Triangles may share vertices. In general vertices are created when a tool is used to create triangles and deleted when all the triangles that use the vertex are deleted. However, it is possible to create a vertex independant of any triangle.

Creating a Vertex

A vertex is created implicitly when triangles are created. Select any tool that creates a geometric shape (such as a cube, sphere, or cylinder) and it will create new vertices for the triangles that it creates. You may also create a vertex without any triangles attached by using the Create Vertex tool.

Note that a vertex that is created implicitly will be deleted implicitly when all the geometry that uses it is deleted. By contrast, a vertex that was created with the Create Vertex tool must be explicitly selected and deleted by the user. To find unused vertices, see the Select Free Vertices command.

Other Vertex Details

If two triangles share a vertex and you want to force them to each have a separate vertex, you can use the Unweld Vertices command. If you want to combine two vertices into one, use the Weld Vertices command. command.

In order for weld to work, the vertices must be very close in 3D space. If the vertices are too far apart you can force them together by using the Snap Together command. You can also enable the Snap To Vertex feature to make it easier to line up vertices with each other.

Vertices can be attached to one or more bone joints to animate geometry in animation mode.

See Also

mm3d-master/doc/html/olh_vertexdetails.page000066400000000000000000000000761324021725400213060ustar00rootroot00000000000000PAGE_TITLE=Vertex Details PAGE_CONTENT=Viewport Settings

The Viewport Settings Window is used to change the grid display in the model viewports. Select Viewport Settings from the Main Window's View menu.

The Default Grid Unit field specifies the default distance between each grid line. There is a separate setting for the canvas and 3D perspective viewports. The number of actual lines drawn depends on the zoom factor of the viewport (the grid spacing doubles or halves as needed).

For the perspective viewport you can specify the number of grid lines that are drawn (in each dimension) using the Grid Lines field. You can turn grid lines on and off for each plane independently using the Plane checkboxes.

Press Ok to keep your changes or press Cancel to ignore any changes.

mm3d-master/doc/html/olh_viewportsettings.page000066400000000000000000000001041324021725400220530ustar00rootroot00000000000000PAGE_TITLE=Viewport Settings PAGE_CONTENT= What's New in MM3D?

Below is a list of new features in version 1.4.

  • General:
    • 64-bit support
    • i18n support
    • Context-sensitive panel for editing properties of selected objects
    • Export selected portions of a model to a separate file
    • Boolean Operations
    • Global transformations (works on entire model, including all animations)
    • Texture projections (cylinder/sphere mapping)
    • Direct vertex coordinate editing
    • Orthographic projections can be rotated to any view angle
    • Flip between orthographic and perpective projections
    • Rotate a viewport on the Z axis
    • Save/restore viewing angle and zoom with keyboard shortcuts
    • Render selected faces in red (instead of rendering just the edges in red)
    • Numerous texture coordinate window improvements
  • Animation / Bone Joints:
    • Converted the animation window to a dockable toolbar
    • Support for multiple bone joint influences on a single vertex
    • Auto-assign bone joint command
  • New Tools:
    • Snap to Grid/Vertex
    • Bolt points
    • Extrude (viewport interactive version of the geometry command)
  • New Commands:
    • Edge turn
    • Edge divide
    • Cap Holes
    • Simplify Mesh
    • Face Out
  • File formats:
    • MD3
    • Cal3D
    • COB
    • DXF
mm3d-master/doc/html/olh_whatsnew.page000066400000000000000000000000761324021725400202630ustar00rootroot00000000000000PAGE_TITLE=What's New in MM3D? PAGE_CONTENT= mm3d-master/doc/html/secleft.htm000066400000000000000000000001751324021725400170620ustar00rootroot00000000000000
mm3d-master/doc/html/secright.htm000066400000000000000000000000621324021725400172400ustar00rootroot00000000000000
mm3d-master/doc/html/template.htm000066400000000000000000000012051324021725400172430ustar00rootroot00000000000000 Misfit Model 3D Help - <TMPL_VAR name="PAGE_TITLE">
[ Contents | Introduction | Tools | Geometry Menu ]
Copyright © 2004-2008, Kevin Worcester
mm3d-master/doc/html/tutorial_outline.txt000066400000000000000000000073451324021725400210740ustar00rootroot00000000000000Meta Data Copyright Add background image Front - proportions Start modeling Cylinder, 4 segments, six sides Have to rotate (hold shift) to get it vertical select vertices and scale to chest size move vertices to match drawing Adjust dimensions in other viewports (but only adjust on the depth axis) edge turn at waist see problem edge, highlight select edge turn see corrected faces edge divide to add detail snap to vertex see also drag vertex hide back faces are getting in the way select, hide selected edge turn All down the side (single before and after picture) unhide Mirror Use boolean operation to cut it half Torso is object A Cube is object B Subtract B from A Simplify mesh Duplicate (note vertex count) Flip Select center vertices weld (note vertex count) Use proportions image in Right viewport Just for depth reference on next to leg Cylinder for leg 6 segments, 8 sides horizontal, rotate to vertical scale to match leg width Connect Remove faces under torso where leg will connect Remove top faces above leg where it will connect with torso snap to vertex to join vertices weld to connect Need to edge turn Finding exact faces in side view can be tricky Switch perspective to ortho and select faces that way Flip back to perspective Do edge turn and see result Move vertices to match up with leg (in side view) Make foot Select bottom faces to make ankle and heel Extrude tool Move toe-side leg vertices up to ankle top, snap nearest and and weld Extrude again to make foot Move vertices to match up with leg (in front view) Leg is kind of curvey, doesn't look natural Go back up leg and adjust vertex postions Duplicate leg, flip, select seam vertices, and weld Make less pigeon toed (100 to 101) Make arm 8 segments, 8 sides, horizontal, don't need to rotate this time Match vertices to reference in front view Extrude where arm will meet shoulder Connect Rotate arm on X axis so that front view is now facing down (palm down) Remove shoulder and arm internal faces in preparation for weld Hide legs, arm, and far side of torso to get a better view Move vertices (snap to vertex for move tool) and weld Adjust vertices from front view again to make the cylinder more arm-shaped Looks kind of octogony, weld some vertices to make the shape look less blocky Make hand Extrude end of arm for hand Extrude side faces to make thumb Move vertices and weld to make thumb look less blocky Add smoothness by splitting faces Weld split faces to reconnect Do some edge turns on the thumb Arm looks good enough for now Don't want to duplicate and connect on to the shoulder on the other side Just delete half of torso, dup and flip along with arm Select all and weld (only near vertices are welded) Head Extrude torso top to make neck Remove neck top faces to make room to attach head Cylinder, 6 segments, 8 sides Horizontal, rotate it Use reference image to scale to basic head size Create visor by moving vertices, edge turning as necessary Shape back of helmet Adjust vertices to match head shape (in Front view) Edge divide and move vertices to create breathing mask area Face shield, duplicate and extrude to create inset Hide helmet to show what it looks like Face shield will be transparent, insde will be visible Connect neck to torso at shoulders Completed geometry (1x1 view) (lacks chest shield) mm3d-master/i18n/000077500000000000000000000000001324021725400137665ustar00rootroot00000000000000mm3d-master/i18n/Makefile.am000066400000000000000000000013641324021725400160260ustar00rootroot00000000000000QMFILES = \ mm3d_de.qm \ mm3d_fr.qm \ mm3d_sk.qm \ mm3d_ref.qm \ mm3d_bork.qm \ qt_ar.qm \ qt_cs.qm \ qt_de.qm \ qt_fr.qm \ qt_iw.qm \ qt_ru.qm \ qt_sk.qm \ qt_zh_CN.qm TSFILES = \ mm3d_ref.ts \ mm3d_de.ts \ mm3d_fr.ts \ mm3d_sk.ts \ mm3d_bork.ts QTFILES = \ qt_ar.ts \ qt_cs.ts \ qt_de.ts \ qt_fr.ts \ qt_iw.ts \ qt_ru.ts \ qt_sk.ts \ qt_zh_CN.ts \ qt_untranslated.ts EXTRA_DIST = \ $(QMFILES) \ $(TSFILES) \ $(QTFILES) BUILT_SOURCES = $(QMFILES) all: tsfiles: lupdate ../src/*.cc ../src/*/*.cc ../src/*.h ../src/*/*.h ../src/qtui/*.ui -ts $(TSFILES) qmfiles: $(QMFILES) %.qm: %.ts $(QT_LRELEASE) $< install: $(INSTALL) -d $(DESTDIR)$(datadir)/mm3d/i18n ${INSTALL} -m 0644 *.qm $(DESTDIR)$(datadir)/mm3d/i18n mm3d-master/i18n/mm3d_bork.ts000066400000000000000000006532171324021725400162310ustar00rootroot00000000000000 AboutWin Misfit Model 3D - About Bork! AlignWin F1 Help Shortcut Bork! Align X Bork! Align Y Bork! Align Z Bork! Align Selected operation complete Bork! AlignWinBase Align Selection Bork! Align X Bork! Align minimum Bork! Align center Bork! Align maximum Bork! 0.0 Bork! Align &X Now Bork! Alt+X Bork! Align Y Bork! Align &Y Now Bork! Alt+Y Bork! Align Z Bork! Align &Z Now Bork! Alt+Z Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! AnimConvertWinBase Convert To Frame Bork! Convert Skeletal to Frame: Bork! AnimName Bork! Frame Anim Name: Bork! Frame Count Bork! F1 for help Bork! Continue Bork! Cancel Bork! Cancel All Bork! AnimConvertWindow F1 Help Shortcut Bork! Convert Skeletal to Frame: Bork! Convert Frame to Frame: Bork! Convert Frame Relative to Frame: Bork! Convert Unknown Type to Frame: Bork! AnimExportWinBase Export Animation Bork! Source Bork! Animation Bork! Viewport Bork! Duration Bork! Iterations Bork! 10 Bork! Seconds Bork! 60 Bork! Output Bork! Directory Bork! Format Bork! anim_0001.jpg Bork! anim_1.jpg Bork! anim_0001.png Bork! anim_1.png Bork! ... Bork! /some/path/name Bork! 25.0 Bork! Frame Rate Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! 1 Bork! 15 Bork! {15?} AnimExportWindow Skeletal - Skeletal Animation prefix Bork! Frame - Frame Animation prefix Bork! [None] No viewport for animation image export Bork! Viewport %1 - Bork! F1 Help Shortcut Bork! Must have more than 0 frames per second Bork! Must have more than 0 seconds of animation Bork! Could not write file: Bork! Output directory does not exist. Bork! AnimSetWinBase Animation Sets Bork! &Down Bork! &Up Bork! &New Bork! &Rename Bork! D&elete Bork! &Copy Bork! &Split Bork! &Join Bork! &Merge Bork! Con&vert To Frame Animation Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! AnimSetWindow Skeletal Animation Bork! Frame Animation Bork! F1 Help Shortcut Bork! Misfit 3D Bork! New name: Bork! copy Bork! Split at frame Split animation frame window title Bork! Split 'Split' refers to splitting an animation into two separate animations Bork! at frame number the frame number where the second (split) animation begins Bork! split Bork! Cannot Split Cannot split animation window title Bork! Must have at least 2 frames to split split animation Bork! Cannot merge animation %1 and %2, frame counts differ. Bork! Can only merge skeletal animations. Bork! Animation changes operation complete Bork! AnimWidget F1 Help Shortcut Bork! <New Animation> Bork! Start animation mode operation complete Bork! New Animation operation complete Bork! Frame: Bork! Set FPS Frames per second, operation complete Bork! Change Frame Count operation complete Bork! Clear frame Remove animation data from frame, operation complete Bork! Paste frame paste frame animation position, operation complete Bork! Paste keyframe Paste keyframe animation data complete Bork! End animation mode operation complete Bork! Frame: n/a Bork! Delete Animation? window title Are you sure you want to delete this animation? Delete Animation Delete animation, operation complete No frame animation data to paste No skeletal animation data to paste AnimWidgetBase Animation Bork! FPS Bork! Play Bork! Stop Bork! Loop Bork! Frames Bork! Frame: 03 Bork! X Bork! Delete Animation AnimWinBase Animation Bork! New Bork! Rename Bork! Delete Bork! Keyframe Bork! Frames Bork! FPS Bork! Frame: 03 Bork! Copy Frame Bork! Paste Frame Bork! Clear Frame Bork! Skeletal Bork! Frame Bork! Play Bork! Stop Bork! Loop Bork! Press F1 for help Bork! Close Bork! AnimWindow F1 Help Shortcut Bork! Misfit 3D Bork! New name: Bork! Animations Bork! AutoAssignJointWin F1 Help Shortcut Bork! AutoAssignJointWinBase Auto-Assign Bone Joints Bork! Only assign to selected joints Bork! Single Bork! Multiple Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! BackgroundSelect All Supported Formats ( All Borked Formats ( Open background image Bork! All Files (*) All Bork! (*) Could not open file Bork! BackgroundSelectBase BackgroundSelect Bork! None Bork! File... Bork! BackgroundWin F1 Help Shortcut Bork! Background Image operation complete Bork! BackgroundWinBase Select Background Image Bork! Front Bork! Back Bork! Left Bork! Right Bork! Top Bork! Bottom Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! BoolPanel Boolean Operation Bork! BoolWin Union boolean operation Bork! Subtraction boolean operation Bork! Intersection boolean operation Bork! You must have at least once face selected Bork! Object A triangles are still selected Bork! Union With Selected boolean operation Bork! Subtract Selected boolean operation Bork! Intersect With Selected boolean operation Bork! Fuse Selected boolean operation Bork! Select faces to set Select faces to set as 'A' Object in boolean operation Bork! BoolWinBase Boolean Operation Bork! Operation Bork! Fuse Bork! Union Bork! Subtraction Bork! Intersection Bork! Set Object A Bork! Select faces to set Bork! Subtract Selected Bork! Cal3dPrompt F1 Help Shortcut Bork! Cal3dPromptBase Cal3D Filter Options Save Meshes All meshes in one file Group meshes by name Save Materials CRF (Binary) XRF (XML Text) Ok Bork! Cancel Bork! Command Align Selected... Bork! Assigning %1 vertices and %2 points to joint %3 Bork! You must have exactly 1 bone joint selected. Bork! Assign Selected to Bone Joint Bork! Set Background Image... Bork! Cap Holes complete Bork! Could not find gap in selected region Bork! Cap Holes Bork! Selected primitives copied Bork! You must have at least 1 face, joint, or point selected to Copy Bork! Copy complete Bork! Copy Selected to Clipboard Bork! Delete Bork! Deleting joints may destroy skeletal animations Do you wish to continue? Bork! Primitives deleted Bork! Selected primitives duplicated Bork! You must have at least 1 face, joint, or point selected to Duplicate Bork! Duplicate complete Bork! Duplicate Bork! Edge Divide complete Bork! You must have at 2 adjacent vertices to Edge Divide Bork! Edge Divide Bork! Edge Turn complete Bork! You must have at least 2 adjacent faces to Edge Turn Bork! Edge Turn Bork! Extrude... Bork! Flatten Bork! Flatten X Bork! Flatten Y Bork! Flatten Z Bork! Need at least 1 vertex, joint, point, or face selected Bork! Selected primitives flattened Bork! Flip Bork! Flip X Bork! Flip Y Bork! Flip Z Bork! Selected primitives flipped Bork! Hide Bork! Hide Unselected Bork! Hide Selected Bork! Unhide All Bork! Selected primitives hidden Bork! Primitives unhidden Bork! Unselected primitives hidden Bork! Selection inverted Bork! Invert Selection Bork! Normals inverted Bork! Invert Normals Bork! Joints... Bork! Make Face From Vertices Bork! Face created Bork! Must select exactly 3 vertices Bork! Paste complete Bork! Paste from Clipboard Bork! Points... Bork! Rotate Texture Coordinates Bork! Face Bork! Group Bork! Texture coordinates rotated Bork! Must select faces Bork! Select Free Vertices Bork! Free-floating vertices selected Bork! Simplify Mesh Bork! Snap Vertices Together Bork! Snap All Selected Bork! Snap Nearest Selected Bork! Snap All and Weld Bork! Snap Nearest and Weld Bork! Spherify... Bork! Subdivide complete Bork! Subdivide Faces Bork! You must have 1 or more vertices selected to unweld. Bork! Unweld Vertices Unbork borks! You must have 2 or more vertices selected to weld. Bork! Weld Vertices Bork borks! Unwelded %1 vertices into %2 vertices Unborked %1 borks into %2 borks Welded %1 vertices into %2 vertices Borked %1 borks into %2 borks! Normals face out Bork! Vertices Bork! Faces Bork! Meshes Bork! Normals Bork! Normals Face Out CommandWidget You are in animation mode, but there are no animations ContextGroup <None> Bork! <New> Bork! New Group Name of new group, window title Bork! Enter new group name: Bork! Set Group operation complete Bork! Unset Group operation complete Bork! Set Material operation complete Bork! Set Projection operation complete Bork! ContextGroupBase Group Bork! Projection Name Bork! ... Bork! Material Name Bork! Group Material: Bork! Group Name Bork! Triangle Projection Bork! Texture Projection Bork! ContextInfluences <None> Bork! Change Joint Assignment operation complete Bork! Change Influence Weight operation complete Bork! Change Influence Type operation complete Bork! <Mixed> multiple types of bone joint influence Bork! Custom bone joint influence Bork! Auto bone joint influence Bork! Remainder bone joint influence Bork! Auto: %1 Bork! Rem: %1 Bork! ContextInfluencesBase Influences Bork! Weight Bork! <Mixed> Bork! Custom Bork! Auto Bork! Remaining Bork! <None> Bork! Joint Bork! ContextName Rename operation complete Bork! ContextNameBase Name Bork! ContextPanel Properties Window title Bork! ContextPosition Set Position operation complete Bork! ContextPositionBase Position Bork! Z Bork! Y Bork! X Bork! Dimensions ContextProjection Set Projection Type operation complete Bork! ContextProjectionBase Projection Bork! Projection Type Bork! Cylinder Bork! Sphere Bork! Plane Bork! ... Bork! ContextRotation Set Rotation operation complete Bork! ContextRotationBase Rotation Bork! Z Bork! Y Bork! X Bork! CubeToolWidget Cube Bork! Segment Bork! CylinderToolWidget Segments Bork! Sides Bork! Width Bork! Scale Bork! DeleteCommand Deleting joints may destroy skeletal animations Do you wish to continue? Bork! Primitives deleted Bork! EditKeyframeWin Set keyframe %1 Bork! EllipsoidToolWidget Smoothness: Bork! Faces: Bork! Sphere Bork! From Center Checkbox that indicates if ellipsoid is created from center or far corner Bork! ErrorObject Success Bork! Canceled Bork! File is an unknown type Bork! Operation not supported for this file type Bork! Invalid argument (internal error) Bork! File does not exist Bork! Permission denied Bork! Could not open file Bork! Could not read from file Bork! File is the wrong type or corrupted Bork! Unsupported version Bork! File contains invalid data Bork! Unexpected end of file Bork! Unknown error Bork! Could not write file Bork! This operation is not supported Bork! Write not supported, try "Export..." Bork! Unrecognized file extension (unknown type) ExtrudeWin F1 Help Shortcut Bork! Extrude complete Bork! Extrude operation complete Bork! ExtrudeWinBase Extrude Bork! Extrude options Bork! X: Bork! 0 Bork! Z: Bork! Y: Bork! Make Back Faces Bork! E&xtrude Bork! Press F1 for help Bork! Close Bork! GroupCleanBase Group Clean-up Window Merge identical materials Remove unused materials Merge identical groups Remove unused groups Ok Bork! Cancel Bork! GroupCleanWin F1 Help Shortcut Bork! Group Clean-up operation complete GroupWinBase Groups Bork! No group Bork! New Bork! Rename Bork! Delete Bork! Select Faces In Group Bork! Unselect Faces In Group Bork! Smoothness: 100 Bork! Max Angle: 000 Bork! Faces Bork! Assign As Group Bork! Add To Group Bork! Texture Bork! No texture Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! GroupWindow F1 Help Shortcut Bork! New group window title Bork! Enter new group name: Bork! Group name must be between 1 and %1 characters Bork! Bad group name window title Bork! Cannot change cannot change group name, window title Bork! You cannot change the default group name Bork! Smoothness: Bork! Max Angle: Bork! Group changes operation complete Bork! HelpWinBase Help Bork! Contents Bork! Back Bork! Forward Bork! Ok Bork! JointWin F1 Help Shortcut Bork! Rename joint window title Bork! Enter new joint name: Bork! Joint changes operation complete Bork! JointWinBase Joints Bork! Rename Bork! Delete Bork! Selection Bork! Select Joint Vertices Bork! Select Unassigned Vertices Bork! Assign Selected to Joint Bork! Add Selected to Joint Bork! F1 for help Bork! Ok Bork! Cancel Bork! KeyConfig V Select Vertices Tool Shortcut V F Select Faces Tool Shortcut F C Select Connected Mesh Tool Shortcut C G Select Groups Tool Shortcut G B Select Bone Joints Tool Shortcut B T Select Points Tool Shortcut T M Move Tool Shortcut M R Rotate Tool Shortcut R H Hide Unselected Command Shortcut H Shift+H Hide Selected Command Shortcut Shift+H ? Unhide All Command Shortcut ? Delete Delete Command Shortcut Delete Ctrl+D Duplicate Command Shortcut Ctrl+D Ctrl+C Copy to Clipboard Command Shortcut Ctrl+C Ctrl+V Paste from Clipboard Command Shortcut Ctrl+V Insert Extrude Command Shortcut Insert Ctrl+W Weld Command Shortcut Ctrl+W Ctrl+N File | New Window Shortcut Ctrl+N Ctrl+O File | Open Shortcut Ctrl+O Ctrl+S File | Save Shortcut Ctrl+S Ctrl+Q File | Quit Shortcut Ctrl+Q Home View | Frame All Shortcut Home Shift+Home View | Frame Selected Shortcut Shift+Home Ctrl+G Groups | Edit Groups Shortcut Ctrl+G Ctrl+M Groups | Edit Materials Shortcut Ctrl+M Ctrl+E Groups | Edit Texture Coordinates Shortcut Ctrl+E Ctrl+B Joints | Assign Selected Shortcut Ctrl+B Shift+U Unhide All Command Shortcut KeyValueWindowBase Edit Meta Data Bork! Name Bork! Value Bork! Ok Bork! Cancel Bork! LicenseWin GNU General Public License Bork! LowLevel Cannot delete root joint Bork! Cannot add or delete because you have frame animations. Try "Merge..." instead. Bork! Success Bork! Canceled Bork! File is an unknown type Bork! Operation not supported for this file type Bork! Invalid argument (internal error, probably null pointer argument) Bork! File does not exist Bork! Permission denied Bork! Could not open file Bork! Could not read from file Bork! File is the wrong type or corrupted Bork! Unsupported version Bork! File contains invalid data Bork! Unexpected end of file Bork! Unknown error Bork! Invalid error code Bork! Could not write file Bork! This operation is not supported Bork! MM3D encountered an unexpected data size problem See Help->About to contact the developers Bork! Model has a texture that is not powers of 2 Bork! Could not load Bork! Model contains no skeletal animations Bork! Model skeletons do not match Bork! This looks like a player model. Do you want to load all sections? Bork! Could not load texture Bork! Write not supported, try "Export..." Bork! Unrecognized file extension (unknown type) MD2 requires all groups to have the same material. MD2 export requires all faces to be grouped. MD3 export requires all faces to be grouped. MD3_PATH+filename is to long. Too many animation frames for MD3 export. Too many points for MD3 export. Too many groups for MD3 export. Too many faces in a single group for MD3 export Too many vertices in a single group for MD3 export Point name is too large for MD3 export. Group name is too large for MD3 export. Texture filename is too long. MM3D does not support CAL3D files in XML format The file does not contain any mesh or animation data MapDirectionBase Which direction? Bork! Set new texture coordinates from which direction? Bork! Front Bork! Back Bork! Left Bork! Right Bork! Top Bork! Bottom Bork! Ok Bork! Cancel Bork! MergeWinBase Merge Model Bork! Merge location Bork! 0.0 Bork! Rotation Bork! Translation Bork! Merge Options Bork! Include textures Bork! Include animations Bork! Animation Options Bork! Append animations Bork! Merge if possible Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! MergeWindow F1 Help Shortcut Bork! Merge models operation complete Bork! MetaWindow F1 Help Shortcut Bork! Name meta value key name Bork! Value meta value 'value' Bork! Change meta data operation complete Bork! MetaWindowBase Name Bork! Value Bork! Model Meta Data Bork! New Bork! Delete Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! ModelViewBase ModelView Bork! Perspective Bork! Front Bork! Back Bork! Left Bork! Right Bork! Top Bork! Bottom Bork! Orthographic Bork! ModelViewport Could not load background %1 Bork! Use the middle mouse button to drag/pan the viewport Bork! OpenGL error = Invalid Value Bork! OpenGL error = Invalid Enum Bork! OpenGL error = Invalid Operation Bork! OpenGL error = Stack Overflow Bork! OpenGL error = Stack Underflow Bork! OpenGL error = Out Of Memory Bork! OpenGL error = Unknown Bork! Ms3dPrompt F1 Help Shortcut Bork! Ms3dPromptBase MS3D Filter Options Format Subversion Subversion 0 Subversion 1 Subversion 2 Subversion Options Vertex Extra FFFFFFFF Ok Bork! Cancel Bork! NewAnimBase New Animation Bork! &Name Bork! Animation Type Bork! &Skeletal Bork! Alt+S Bork! &Frame Bork! Alt+F Bork! &Ok Bork! Alt+O Bork! &Cancel Bork! Alt+C Bork! ObjPrompt F1 Help Shortcut Bork! ObjPromptBase OBJ Filter Options Bork! &Save normals Bork! Alt+S Bork! &Normal Decimal Places Bork! &Texture Decimal Places Bork! &Vertex Decimal Places Bork! Ok Bork! Cancel Bork! PaintTextureWin F1 Help Shortcut Bork! File name for saved texture? Bork! File exists. Overwrite? Bork! Could not write file: Bork! PaintTextureWinBase Paint Texture Bork! Polygons: Bork! Edges Bork! Filled Bork! Filled and Edges Bork! Vertices Bork! Hidden Bork! Visible Bork! Clear Background Bork! Save Size: Bork! 64 Bork! 128 Bork! 256 Bork! 512 Bork! 1024 Bork! 2048 Bork! x Bork! Save Texture... Bork! Press F1 for help Bork! Close Bork! PluginWinBase Plugin Bork! Version Bork! Description Bork! Status Bork! Plugins Bork! Press F1 for help Bork! Ok Bork! PluginWindow F1 Help Shortcut Bork! PointWin F1 Help Shortcut Bork! Rename point window title Bork! Enter new point name: Bork! Point changes operation complete Bork! PointWinBase Points Bork! Rename Bork! Delete Bork! Bone Joint Bork! (none) Bork! F1 for help Bork! Ok Bork! Cancel Bork! PolyToolWidget Fan Bork! Poly Type Strip Triangle strip option Fan Triangle fan option Bork! ProjToolWidget Type Cylinder Cylinder projection type Bork! Sphere Sphere projection type Bork! Plane Plane projection type Bork! ProjectionWin F1 Help Shortcut Bork! Ctrl+Z Undo Ctrl+Z Ctrl+Y Redo Ctrl+Y Set Projection Type operation complete Bork! Set Triangle Projection operation complete Bork! Apply Projection operation complete Bork! Reset UV Coordinates operation complete Bork! Rename projection window title Bork! Enter new point name: Bork! Rename Projection operation complete Bork! CTRL+Z Undo shortcut CTRL+Y Redo shortcut ProjectionWinBase Texture Projection Bork! Material Bork! Test Pattern Bork! Cylinder Bork! Sphere Bork! Plane Bork! Show: Bork! Type: Bork! Rename Bork! Zoom: Bork! 1.0 Bork! Remove Faces Bork! Add Faces to Projection Bork! Apply Projection Bork! Reset UV Range Bork! Press F1 for help Bork! Close Bork! RgbaWin F1 Help Shortcut Bork! RgbaWinBase RGBA Window Bork! Light Property Bork! 0.00 Bork! Red Bork! Green Bork! Blue Bork! Alpha Bork! Close Bork! RotateToolWidget X Bork! Y Bork! Z Bork! ScaleToolWidget Proportion Bork! Free Free scaling option Bork! Keep Aspect 2D 2D scaling aspect option Bork! Keep Aspect 3D 3D scaling aspect option Bork! Point Bork! Center Scale from center Bork! Far Corner Scale from far corner Bork! SelectFaceToolWidget Include Back-facing Bork! SpherifyWin Spherify operation complete Bork! StartPrompt F1 Help Shortcut Bork! StatusBar V: Vertices status bar label Bork! F: Faces status bar label Bork! G: Groups status bar label Bork! B: Bone Joints status bar label Bork! P: Points status bar label Bork! M: Materials status bar label Bork! StatusBarBase Form1 Bork! Status text Bork! V:0 Bork! F:0 Bork! G:0 Bork! B:0 Bork! P:0 Bork! T:0 Bork! TextWinBase Text Window Bork! Ok Bork! TextureCoord Reset coordinates? window title Bork! Are you sure you want to reset texture coordinates for this group? Bork! Move texture coordinates Bork! F1 Help Shortcut Bork! CTRL+Z Undo shortcut CTRL+Y Redo shortcut Select texture coordinates TextureCoordBase Texture Coordinates Bork! Zoom: Bork! 1.0 Bork! Mouse Tool Bork! Select Bork! Move Bork! Scale Bork! Scale Options Bork! Scale from center Bork! Keep aspect ratio Bork! Map Scheme Bork! Triangle Bork! Quad Bork! Group Bork! Reset Coordinates Bork! Press F1 for help Bork! Close Bork! Rotate Bork! Lines Black Blue Bork! Green Bork! Cyan Red Bork! Magenta Yellow White Selection Bork! Rotate CCW Rotate CW V Flip H Flip TextureWindow All Supported Formats ( all texture formats All Borked Formats ( Open texture image Bork! All Files (*) All Bork! (*) Could not open file Bork! Color Material window title Bork! Enter new material name: Bork! Rename texture window title Bork! Enter new texture name: Bork! Texture changes Bork! Shininess Bork! Red Bork! Change texture... Change material's texture file Bork! Set texture... Add texture file to material Bork! F1 Help Shortcut Bork! TextureWindowBase Materials Bork! None Bork! New Material... Bork! Rename Bork! Delete Bork! Wrap X Bork! Clamp X Bork! Wrap Y Bork! Clamp Y Bork! Change Texture... Bork! X Bork! Remove texture Bork! Flat Preview Bork! 3D Preview Bork! 0.00 Bork! Alpha Bork! Green Bork! Blue Bork! Red Bork! Ambient Bork! Diffuse Bork! Specular Bork! Emissive Bork! Shininess Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! Tool Attract Far Bork! Attracting far selected primitives Bork! Attract far complete Bork! Attract Near Bork! Attracting near selected primitives Bork! Attract near complete Bork! Move Background Image Bork! Moving background image Bork! Cannot move background from 3D view Bork! Background move complete Bork! Move background image Bork! Scale Background Image Bork! Scaling background image Bork! Cannot scale background from 3D view Bork! Background scale complete Bork! Scale background image Bork! Cube created Bork! Create Cube Bork! Cylinder created Bork! Create Cylinder Bork! Ellipsoid created Bork! Create Ellipsoid Bork! Joint created Bork! Root joint created Bork! Create Bone Joint Bork! Moving selected primitives Bork! Move complete Bork! Tip: Hold shift to restrict movement to one dimension Bork! Move Bork! Point created Bork! Create Point Bork! Create Polygon Bork! Projection created Bork! Create Projection Bork! Rectangle created Bork! Create Rectangle Bork! Tip: Hold shift to rotate in 15 degree increments Bork! Rotating selected primitives Bork! Setting rotation point Bork! Rotate complete Bork! Rotate Bork! Scale Bork! Scaling selected primitives Bork! Scale complete Bork! Tip: Hold shift to restrict scaling to one dimension Bork! Starting selection Bork! Selection complete Bork! Select Bone Joints Bork! Select Connected Mesh Bork! Select Faces Bork! Select Groups Bork! Select Points Bork! Select Projections Bork! Select Vertices Bork! Shear Bork! Starting shear on selected primitives Bork! Shear complete Bork! Torus created Bork! Create Torus Bork! Vertex created Bork! Create Vertex Bork! Dragging selected vertex Bork! Must a vertex selected Bork! Drag complete Bork! Drag Vertex on Edge Bork! Extrude complete Bork! Extrude Bork! Must have faces selected to extrude Bork! Extruding selected faces Bork! Select Bork! Attract Bork! Background Image Bork! Create Other Bork! TorusToolWidget Segments Bork! Sides Bork! Width Bork! Circle Bork! From Center Checkbox that indicates if torus is created from center or from far corner Bork! TransformWindow Matrix Translate Bork! Matrix Rotate Bork! Matrix Rotate On Axis Bork! Matrix Scale Bork! Apply Matrix Bork! Transform Cannot Be Undone window title Bork! This transformation cannot be undone. Bork! Are you sure you wish to continue? Bork! Apply Transformation button Bork! Cancel Transformation button Bork! F1 Help Shortcut Bork! TransformWindowBase Transform Model Bork! 0 Bork! X Bork! Y Bork! Z Bork! Translate Bork! Euler Angles Bork! Rotate Bork! Quaternion Bork! Angle Bork! Axis Bork! 1.0 Bork! Scale Bork! 1 Bork! (bottom row is translation) Bork! Apply Matrix Bork! Matrix Bork! Apply to: Bork! Entire Model and Animations Bork! Press F1 for help Bork! Close Bork! Selected (including animations) Entire Model (including animations) ValueWin F1 Help Shortcut Bork! ValueWinBase Value Window Bork! Value Bork! Press F1 for help Bork! Ok Bork! Cancel Bork! ViewWindow Some models are unsaved. Save before exiting? Bork! Press F1 for help using any window Bork! Animations Bork! Properties Bork! New File|New Bork! Open File|Open Bork! Save File|Save Bork! Save As File|Save As Bork! Set Background Image... File|Set Background Image Bork! Run Script... File|Run Script Bork! Recent Scripts File|Recent Script Bork! Merge... File|Merge Bork! Merge Animations... File|Merge Animations Bork! Recent Models File|Recent Models Bork! Plugins... File|Plugins Bork! Close File|Close Bork! Quit File|Quit Bork! Hide Joints View|Hide Joints Bork! Draw Joint Lines View|Draw Joint Lines Bork! Draw Joint Bones View|Draw Joint Bones Bork! Draw Texture Projections View|Draw Texture Projections Bork! Hide Texture Projections View|Hide Texture Projections Bork! Use Red Error Texture View|Use Red Error Texture Bork! Use Blank Error Texture View|Use Blank Error Texture Bork! Render 3D Lines View|Render 3D Lines Bork! Hide 3D Lines View|Hide 3D Lines Bork! Draw Back-facing Triangles View|Draw Back-facing Triangles Bork! Hide Back-facing Triangles View|Hide Back-facing Triangles Bork! Frame All View|Frame Bork! Frame Selected View|Frame Bork! Show Properties View|Show Properties Bork! Render Options View|Render Options Bork! 3D Wireframe View|3D Bork! 3D Flat View|3D Bork! 3D Smooth View|3D Bork! 3D Texture View|3D Bork! 3D Alpha Blend View|3D Bork! Canvas Wireframe View|Canvas Bork! Canvas Flat View|Canvas Bork! Canvas Smooth View|Canvas Bork! Canvas Texture View|Canvas Bork! Canvas Alpha Blend View|Canvas Bork! 1 View View|Viewports Bork! 1x2 View View|Viewports Bork! 2x1 View View|Viewports Bork! 2x2 View View|Viewports Bork! 2x3 View View|Viewports Bork! 3x2 View View|Viewports Bork! 3x3 View View|Viewports Bork! Viewport Settings... View|Viewport Settings Bork! Grid Tools|Snap to Grid Bork! Vertex Tools|Snap to Vertex Bork! Undo Bork! Ctrl+Z Undo shortcut Bork! Redo Bork! Ctrl+Y Redo shortcut Bork! Snap To Bork! Tools Bork! Edit Groups... Groups|Edit Groups Bork! Edit Materials... Groups|Edit Materials Bork! Reload Textures Groups|Reload Textures Bork! Edit Projection... Groups|Edit Projection Bork! Edit Texture Coordinates... Groups|Edit Texture Coordinates Bork! Paint Texture... Groups|Paint Texture Bork! Boolean Operation... Groups|Boolean Operation Bork! Edit Model Meta Data... Groups|Edit Model Meta Data Bork! Transform Model... Groups|Transform Model Bork! Edit Joints... Joints|Edit Joints Bork! Assign Selected to Joint Joints|Assign Selected to Joint Bork! Remove All Influences from Selected Joints|Remove All Influences from Selected Bork! Remove Selected Joint from Influencing Joints|Remove Selected Joint from Influencing Bork! Convert Multiple Influences to Single Joints|Convert Multiple Influences to Single Bork! Select Joint Influences Joints|Select Joint Influences Bork! Select Influenced Vertices Joints|Select Influenced Vertices Bork! Select Influenced Points Joints|Select Influenced Points Bork! Select Unassigned Vertices Joints|Select Unassigned Vertices Bork! Select Unassigned Points Joints|Select Unassigned Points Bork! Start Animation Mode... Animation|Start Animation Mode Bork! Stop Animation Mode Animation|Stop Animation Mode Bork! Animation Sets... Animation|Animation Sets Bork! Export Animation... Animation|Export Animation Bork! Copy Animation Frame Animation|Copy Animation Frame Bork! Paste Animation Frame Animation|Paste Animation Frame Bork! Clear Animation Frame Animation|Clear Animation Frame Bork! Set Rotation Keyframe Animation|Set Rotation Keyframe Bork! Set Translation Keyframe Animation|Set Translation Keyframe Bork! Contents... Help|Contents Bork! License... Help|License Bork! About... Help|About Bork! &File menu bar Bork! &View menu bar Bork! &Tools menu bar Bork! &Primitives menu bar Bork! &Groups menu bar Bork! &Influences menu bar Bork! &Animation menu bar Bork! &Help menu bar Bork! All Supported Formats ( All Borked Formats ( ;; All Files (*) ;; All Bork! (*) All Files (*) All Bork! (*) Save model file as Bork! File exists. Overwrite? Bork! All Supported Formats ( model formats All Borked Formats ( Open model file Bork! Merge models Bork! : Bork! Script %1 complete Bork! Script %1 error %2 Bork! Save first? Bork! Model has been modified Do you want to save before closing? Bork! Unknown response: %1, Canceling close request Bork! Hide Properties View|Hide Properties Bork! Cannot hide with selected projections. Unselect projections now? Bork! Hide projections Bork! Cannot hide with selected joints. Unselect joints now? Bork! Hide bone joints Bork! You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'edit texture coordinates' window Bork! You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'paint texture' window Bork! Undo %1 Bork! Nothing to undo Bork! Redo %1 Bork! Nothing to redo Bork! This model does not have any animations Bork! Set rotation keframe Bork! Set translation keframe Bork! Unknown response: Canceling operation Bork! [unnamed] For filename in title bar (if not set) Bork! assigning %1 vertices and %2 points to joints Bork! Assign Selected to Joint Bork! You must have at least one bone joint selected. Bork! Remove All Influences from Selected Bork! Remove Joint from Influencing Bork! Convert To Single Influence Bork! Select Unassigned Vertices Bork! Select Unassigned Points Bork! Select Joint Influences Bork! Select Influences Vertices Bork! Select Influenced Points Bork! Auto-Assign Selected... Joints|Auto-Assign Selected Bork! Auto-Assign Selected to Bone Joints Bork! You must have at least one vertex or point selected. Bork! Open... File|Open Bork! Save As... File|Save As Bork! Export... File|Export Bork! Edit Model Meta Data... Model|Edit Model Meta Data Bork! Transform Model... Model|Transform Model Bork! Boolean Operation... Model|Boolean Operation Bork! Set Background Image... Model|Set Background Image Bork! Merge... Model|Merge Bork! Import Animations... Model|Import Animations Bork! Save Animation Images... Animation|Save Animation Images Bork! Copy Selected Keyframes Animation|Copy Animation Frame Bork! Paste Selected Keyframes Animation|Paste Animation Frame Bork! &Model menu bar Bork! &Geometry menu bar Bork! Mate&rials menu bar Bork! All Exportable Formats Bork! All Writable Formats Bork! Export model Bork! All Supported Formats model formats Bork! All Supported Formats Bork! F1 Help Shortcut Bork! Export Selected... File|Export Selected You must have at least 1 face, joint, or point selected to Export Selected Clean Up Groups... Groups|Clean Up Groups ViewportSettings F1 Help Shortcut Bork! ViewportSettingsBase Viewport Settings Bork! Canvas Grid Bork! Default Grid Unit Bork! 3D Grid Bork! Grid Lines Bork! X/Y Plane Bork! X/Z Plane Bork! Y/Z Plane Bork! Press F1 for help Bork! &Ok Bork! Alt+O Bork! &Cancel Bork! Alt+C Bork! Decimal Grid Binary Grid Fixed Grid mm3d-master/i18n/mm3d_de.ts000066400000000000000000006564661324021725400156750ustar00rootroot00000000000000 AboutWin Misfit Model 3D - About Über Misfit Model 3D AlignWin F1 Help Shortcut F1 Align X Ausrichten X Align Y Ausrichten Y Align Z Ausrichten Z Align Selected operation complete Ausgewählte ausrichten AlignWinBase Align Selection Auswahl ausrichten Align X Ausrichten X Align minimum Ausrichten Minimum Align center Ausrichten Zentrum Align maximum Ausrichten Maximum 0.0 0.0 Align &X Now Richte &X jetzt aus Alt+X Alt+X Align Y Ausrichten Y Align &Y Now Richte &Y jetzt aus Alt+Y Alt+Y Align Z Ausrichten Z Align &Z Now Richte &Z jetzt aus Alt+Z Alt+Z Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen AnimConvertWinBase Convert To Frame In Frame umwandeln Convert Skeletal to Frame: Wandle Skelet in Frame um: AnimName Animationsname Frame Anim Name: Frame Animationsname: Frame Count Frame Anzahl F1 for help F1 für Hilfe Continue Fortsetzen Cancel Abbrechen Cancel All Alles abbrechen AnimConvertWindow F1 Help Shortcut F1 Convert Skeletal to Frame: Wandle Skelet in Frame um: Convert Frame to Frame: Wandle Frame in Frame um: Convert Frame Relative to Frame: Wandle relativen Frame in Frame um: Convert Unknown Type to Frame: Wandle unbekannten Typ in Frame um: AnimExportWinBase Export Animation Animation exportieren Source Quelle Animation Animation Viewport Viewport Duration Dauer Iterations Schritte Seconds Sekunden Output Ausgabe Directory Verzeichnis Format Format anim_0001.jpg anim_0001.jpg anim_1.jpg anim_1.jpg anim_0001.png anim_0001.png anim_1.png anim_1.png ... ... /some/path/name /irgend/ein/pfad 25.0 25.0 Frame Rate Frame Rate Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen 1 1 15 15 AnimExportWindow Skeletal - Skeletal Animation prefix Skelet - Frame - Frame Animation prefix Frame - [None] No viewport for animation image export [Leer] Viewport %1 - Viewport %1 - F1 Help Shortcut F1 Must have more than 0 frames per second Es müssen mehr als 0 Frames pro Sekunde sein Must have more than 0 seconds of animation Es müssen mehr als 0 Sekunden Animation sein Could not write file: Konnte Datei nicht speichern: Output directory does not exist. Ausgabeverzeichnis existiert nicht. AnimSetWinBase Animation Sets Animations Sets &Down &Runter &Up &Hoch &New &Neu &Rename &Umbennen D&elete &Löschen &Copy &Kopieren &Split &Trennen &Join &Zusammenführen &Merge &Vereinen Con&vert To Frame Animation &In Frame Animation wandeln Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen AnimSetWindow Skeletal Animation Skelet Animation Frame Animation Frame Animation F1 Help Shortcut F1 Misfit 3D Misfit 3D New name: Neuer Name: Split at frame Split animation frame window title Trenne einen Frame Split 'Split' refers to splitting an animation into two separate animations Trennen at frame number the frame number where the second (split) animation begins bei Frame Nummer Cannot Split Cannot split animation window title Kann nicht trennen Must have at least 2 frames to split split animation Es müssen mindestens 2 Frames existieren um zu trennen Cannot merge animation %1 and %2, frame counts differ. Kann Animation %1 und %2 nicht trennen, Frame Anzahl ist unterschiedlich. Can only merge skeletal animations. Es können nur Skelet Animationen zusammengefügt werden. Animation changes operation complete Änderungen an Animation copy kopieren split trennen AnimWidget <New Animation> <Neue Animation> Start animation mode operation complete Starte Animations Modus New Animation operation complete Neue Animation Frame: Frame: Set FPS Frames per second, operation complete Setze FPS Change Frame Count operation complete Ändere Frame Anzahl Clear frame Remove animation data from frame, operation complete Frame zurücksetzen Paste frame paste frame animation position, operation complete Frame einfügen Paste keyframe Paste keyframe animation data complete KeyFrame einfügen End animation mode operation complete Beende Animationsmodus Frame: n/a Frame: -kein- Delete Animation? window title Animation löschen? Are you sure you want to delete this animation? Sind Sie sicher, dass sie diese Animation löschen wollen? Delete Animation Delete animation, operation complete Lösche Animation No frame animation data to paste Keine Frame Animationsdaten zum einfügen No skeletal animation data to paste Keine Skelet Animationsdaten zum einfügen AnimWidgetBase Animation Animation FPS FPS Play Abspielen Stop Stop Loop Wiederholen Frames Frames Frame: 03 Frame: 03 X X Delete Animation Lösche Animation AnimWindow Animations Animationen AutoAssignJointWin F1 Help Shortcut F1 AutoAssignJointWinBase Auto-Assign Bone Joints Verknüpfe Knochengelenke automatisch Only assign to selected joints Weise nur den ausgewählten Gelenken zu Single Einzel Multiple Multi Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen BackgroundSelect All Supported Formats ( Alle unterstützten Formate ( Open background image Öffne Hintergrund Bild Could not open file Konnte Datei nicht öffnen BackgroundSelectBase BackgroundSelect HintergrundAuswahl None Kein File... Datei... BackgroundWin F1 Help Shortcut F1 Background Image operation complete Hintergrund Bild BackgroundWinBase Select Background Image Wähle Hintergrund Bild aus Front Vorne Back Hinten Left Links Right Rechts Top Oben Bottom Unten Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen BoolPanel Boolean Operation Boolsche Operation BoolWin Union boolean operation Union Subtraction boolean operation Subtraktion Intersection boolean operation Intersektion You must have at least once face selected Sie müssen mindestens eine Fläche auswählen Object A triangles are still selected Dreiecke von Objekt A sind noch ausgewählt Union With Selected boolean operation Einheit mit Ausgewählten Subtract Selected boolean operation Subtrahiere Ausgewählte Intersect With Selected boolean operation Intersektion mit Ausgewählten Fuse Selected boolean operation Verschweiße? Ausgewählte Select faces to set Select faces to set as 'A' Object in boolean operation Wähle Flächen zum setzten aus BoolWinBase Boolean Operation Boolsche Operation Operation Operation Fuse Verschweiße?_ Union Union Subtraction Subtraktion Intersection Intersektion Set Object A Setze Objekt A Select faces to set Wähle Flächen zum setzten aus Subtract Selected Subtrahiere Ausgewählte Cal3dPrompt F1 Help Shortcut F1 Cal3dPromptBase Cal3D Filter Options Cal3D Filter Optionen Save Meshes Meshes speichern All meshes in one file Alle Meshes in einer Datei Group meshes by name Gruppiere Meshes nach Name Save Materials Speichere Materialien CRF (Binary) CRF (Binary) XRF (XML Text) XRF (XML Text) Ok Ok Cancel Abbrechen Command Align Selected... Ausgewählte ausrichten... Assigning %1 vertices and %2 points to joint %3 Verknüpfe %1 Vertizes und %2 Punkte mit Gelenk %3 You must have exactly 1 bone joint selected. Sie müssen genau ein Knochen Gelenk ausgewählt haben. Assign Selected to Bone Joint Weise Ausgewählte dem Knochen Gelenk zu Set Background Image... Setze Hintergrund Bild... Cap Holes complete Stopfe Löcher vollständig Could not find gap in selected region Konnte keine Lücke in der ausgewählten Region finden Cap Holes Stopfe Löcher Selected primitives copied Ausgewählte Primitives kopiert You must have at least 1 face, joint, or point selected to Copy Sie müssen mindestens eine Fläche, Gelenk oder Punkt zum Kopieren auswählen Copy Selected to Clipboard Kopiere Auswahl auf Zwischenablage Delete Löschen Deleting joints may destroy skeletal animations Do you wish to continue? Wenn Sie diese Gelenke Löschen, könnten Skeletanimationen beschädigt werden Wollen sie fortfahren? Primitives deleted Primitives gelöscht Selected primitives duplicated Ausgewählte Primitives dupliziert You must have at least 1 face, joint, or point selected to Duplicate Sie müssen mindestens eine Fläche, Gelenk oder Punkt zum Duplizieren auswählen Duplicate complete Duplikation komplett Duplicate duplizieren Edge Divide complete Edge-Trennen komplett You must have at 2 adjacent vertices to Edge Divide Edge Divide Edge-Trennen Edge Turn complete Edge Drehung komplett You must have at least 2 adjacent faces to Edge Turn Edge Turn Edge-Drehen Extrude... Extrudieren... Flatten Abflachen Flatten X Abflachen X Flatten Y Abflachen Y Flatten Z Abflachen Z Need at least 1 vertex, joint, point, or face selected Sie müssen mindestens eine Fläche, Vertex, Gelenk oder Punkt ausgewählt haben Selected primitives flattened Ausgewählte Primitives abgeflacht Flip Umdrehen Flip X Umdrehen X Flip Y Umdrehen Y Flip Z Umdrehen Z Selected primitives flipped Ausgewählte Primitives umgedreht Hide Verstecken Hide Unselected Verstecke Nicht-Ausgewähltes Hide Selected Verstecke Auswahl Unhide All Verstecktes wieder anzeigen Selected primitives hidden Ausgewählte Primitves versteckt Primitives unhidden Versteckte Primitives wieder angezeigt Unselected primitives hidden Nicht ausgewählte Primitives versteckt Selection inverted Auswahl invertiert Invert Selection Invertiere Auswahl Normals inverted Normale invertiert Invert Normals Invertiere Normale Joints... Gelenke... Make Face From Vertices Mache Fläche aus Vertizes Face created Fläche erstellt Must select exactly 3 vertices Es müssen genau 3 Vertizes ausgewählt sein Paste complete Einfügen komplett Paste from Clipboard Einfügen aus Zwischenablage Points... Punkte... Rotate Texture Coordinates Rotiere Textur-Koordinaten Face Fläche Group Gruppe Texture coordinates rotated Textur-Koordinaten rotiert Must select faces Flächen müssen ausgewählt sein Select Free Vertices Wähle freie Vertizes aus Free-floating vertices selected Frei-schwebende Vertizes ausgewählt Simplify Mesh Mesh vereinfachen Snap Vertices Together Führe Vertizes zusammen Snap All Selected Führe Alle Ausgewählten zusammen Snap Nearest Selected Führe Nächstliegende innerhalb Auswahl zusammen Snap All and Weld Führe alle zusammen und verschmelze Snap Nearest and Weld Führe Nächstliegende zusammen und verschmelze Spherify... Subdivide complete Subdivision komplett Subdivide Faces Flächen Subdividieren You must have 1 or more vertices selected to unweld. Sie müssen 1 oder mehrere Vertizes auswählen um zu trennen. Unweld Vertices Trenne Vertizes You must have 2 or more vertices selected to weld. Sie müssen mindestens 2 oder mehr Vertizes auswählen um zu verschmelzen. Weld Vertices Verschmelze Vertizes Unwelded %1 vertices into %2 vertices Habe %1 Vertizes getrennt in %2 Vertizes Welded %1 vertices into %2 vertices 1% Vertizes zu 2% Vertizes verschmolzen Normals Face Out Normale nach Außen ausrichten Meshes Meshes Normals Normale Vertices Vertizes Faces Flächen CommandWidget You are in animation mode, but there are no animations Sie befinden sich im Animationsmodus, aber es gibt keine Animationen ContextGroup <None> <kein> <New> <Neu> New Group Name of new group, window title Neue Gruppe Enter new group name: Gruppenname für neue Gruppe eingeben: Set Group operation complete Setzte Gruppe Unset Group operation complete UnSetzte Gruppe Set Material operation complete Setzte Material Set Projection operation complete Setze Projektion ContextGroupBase Group Gruppe Projection Name Projektionsname ... ... Material Name Material Name Group Material: Gruppen Material: Group Name Gruppen Name Texture Projection Textur Projektion ContextInfluences <None> <kein> Change Joint Assignment operation complete Ändere Gelenk Zuweisung Change Influence Weight operation complete Change Influence Type operation complete <Mixed> multiple types of bone joint influence <Gemischt> Custom bone joint influence Manuell Auto bone joint influence Automatisch Remainder bone joint influence Verbleibender Auto: %1 Auto: %1 Rem: %1 Verbl: %1 ContextInfluencesBase Influences ?Einflüsse Weight Gewicht Custom Manuell Auto Automatisch Remaining Verbleibend <None> <Kein> Joint Gelenk <Mixed> <Gemischt> ContextName Rename operation complete Umbenennen ContextNameBase Name Name ContextPanel Properties Window title Eigenschaften ContextPosition Set Position operation complete Setze Position ContextPositionBase Position Position Z Z Y Y X X Dimensions ContextProjection Set Projection Type operation complete Setze Projektions Typ ContextProjectionBase Projection Projektion Projection Type Projektions Typ Cylinder Zylinder Sphere Sphäre Plane Ebene ... ... ContextRotation Set Rotation operation complete Setze Rotation ContextRotationBase Rotation Rotation Z Z Y Y X X CubeToolWidget Cube Würfel Segment Segment CylinderToolWidget Segments Segmente Sides Seiten Width Breite Scale Skalieren EllipsoidToolWidget Smoothness: Glätte: Faces: Flächen: Sphere Sphäre From Center Checkbox that indicates if ellipsoid is created from center or far corner von Mitte aus ErrorObject Success Erfolgreich Canceled Abgebrochen Operation not supported for this file type Operation wird für diesen Dateityp nicht unterstützt Invalid argument (internal error) Ungültiges Argument (interner Fehler) File does not exist Datei existiert nicht Permission denied Zugriff verweigert Could not open file Konnte Datei nicht öffnen Could not read from file Konnte nicht von Datei lesen File is the wrong type or corrupted Datei ist vom falschen Typ oder beschädigt Unsupported version Nicht unterstützte Version File contains invalid data Datei enthält ungültige Daten Unexpected end of file Unerwartetes Dateiende Unknown error Unbekannter Fehler Could not write file Konnte Datei nicht speichern This operation is not supported Operation wird nicht unterstützt Write not supported, try "Export..." Schreiben wird nicht unterstützt, versuchen sie "Exportieren..." Unrecognized file extension (unknown type) Unbekannte Dateierweiterung (unbekannter Typ) ExtrudeWin F1 Help Shortcut F1 Extrude complete Extrudieren abgeschlossen Extrude operation complete Extrudieren ExtrudeWinBase Extrude Extrudieren Extrude options Extrudieren Optionen X: X: 0 0 Z: Z: Y: Y: Make Back Faces Erstelle Rückseiten von Flächen E&xtrude &Extrudieren Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Close Schließen GroupCleanBase Group Clean-up Window Merge identical materials Remove unused materials Merge identical groups Remove unused groups Ok Ok Cancel Abbrechen GroupCleanWin F1 Help Shortcut F1 Group Clean-up operation complete GroupWinBase Groups Gruppen No group Keine Gruppe New Neu Rename Umbenennen Delete Löschen Select Faces In Group Wähle Flächen in Gruppe aus Unselect Faces In Group Flächen in Gruppe De-Selektieren Smoothness: 100 Glätte: 100 Max Angle: 000 Maximaler Winkel: 000 Faces Flächen Assign As Group Als Gruppe zuweisen Add To Group zu Gruppe hinzufügen Texture Textur No texture Keine Textur Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen GroupWindow F1 Help Shortcut F1 New group window title Neue Gruppe Enter new group name: Gruppenname für neue Gruppe eingeben: Group name must be between 1 and %1 characters Gruppenname muss zwischen 1 und %1 Zeichen lang sein Bad group name window title Ungültiger Gruppenname Cannot change cannot change group name, window title Kann nicht Änderen You cannot change the default group name Sie können den standard Gruppenname nicht ändern Smoothness: Glätte: Max Angle: Maximaler Winkel: Group changes operation complete Gruppen Änderungen HelpWinBase Help Hilfe Contents Inhalt Back Zurück Forward Vorwärts Ok Ok JointWin F1 Help Shortcut F1 Rename joint window title Gelenk umbenennen Enter new joint name: Neuen Namen für Gelenk eingeben: Joint changes operation complete Gelenk Änderungen JointWinBase Joints Gelenke Rename Umbenennen Delete Löschen Selection Auswahl Select Joint Vertices Wähle Gelenk Vertizes aus Select Unassigned Vertices Wähle nicht-zugewiesene Vertizes Assign Selected to Joint Weise Auswahl Gelenk zu Add Selected to Joint Füge Auswahl zu Gelenk hinzu F1 for help F1 für Hilfe Ok Ok Cancel Abbrechen KeyConfig V Select Vertices Tool Shortcut V F Select Faces Tool Shortcut F C Select Connected Mesh Tool Shortcut C G Select Groups Tool Shortcut G B Select Bone Joints Tool Shortcut B T Select Points Tool Shortcut T M Move Tool Shortcut M R Rotate Tool Shortcut R H Hide Unselected Command Shortcut H Shift+H Hide Selected Command Shortcut Shift+H Delete Delete Command Shortcut Löschen Ctrl+D Duplicate Command Shortcut Strg+D Ctrl+C Copy to Clipboard Command Shortcut Strg+C Ctrl+V Paste from Clipboard Command Shortcut Strg+V Insert Extrude Command Shortcut Einfügen Ctrl+W Weld Command Shortcut Strg+W Ctrl+N File | New Window Shortcut Strg+N Ctrl+O File | Open Shortcut Strg+O Ctrl+S File | Save Shortcut Strg+S Ctrl+Q File | Quit Shortcut Strg+Q Home View | Frame All Shortcut Pos1 Shift+Home View | Frame Selected Shortcut Shift+Pos1 Ctrl+G Groups | Edit Groups Shortcut Strg+G Ctrl+M Groups | Edit Materials Shortcut Strg+M Ctrl+E Groups | Edit Texture Coordinates Shortcut Strg+E Ctrl+B Joints | Assign Selected Shortcut Strg+B Shift+U Unhide All Command Shortcut Shift+U KeyValueWindowBase Edit Meta Data Editiere Meta Daten Name Name Value Wert Ok Ok Cancel Abbrechen LicenseWin GNU General Public License GNU General Public Lizenz LowLevel Cannot delete root joint Kann dieses Wurzelgelenk nicht löschen Cannot add or delete because you have frame animations. Try "Merge..." instead. ?Kann nicht hinzufügen oder löschen, da sie Frame Animationen haben. Versuchen Sie "Zusammenfügen..." stattdessen. Success Erfolgreich Canceled Abgebrochen Operation not supported for this file type Operation wird für diesen Dateityp nicht unterstützt Invalid argument (internal error, probably null pointer argument) Ungültiges Argument (interner Fehler, offenbar "null pointer argument") File does not exist Datei existiert nicht Permission denied Zugriff verweigert Could not open file Konnte Datei nicht öffnen Could not read from file Konnte nicht von Datei lesen File is the wrong type or corrupted Datei ist vom falschen Typ oder beschädigt Unsupported version Nicht unterstützte Version File contains invalid data Datei enthält ungültige Daten Unexpected end of file Unerwartetes Dateiende Unknown error Unbekannter Fehler Invalid error code Ungültiger Fehlercode Could not write file Konnte Datei nicht speichern This operation is not supported Operation wird nicht unterstützt MM3D encountered an unexpected data size problem See Help->About to contact the developers MM3D hat ein unerwartetes Datengröße Problem festgestellt Bitte sehen sie unter Hilfe->Über... nach, um die Entwickler zu kontaktieren Model has a texture that is not powers of 2 Model hat eine Texturgröße die keine 2er-Potenz ist (128x128, 256x256, ...) Could not load Konnte nicht laden Model contains no skeletal animations Model enthält keine Skelet Animationen Model skeletons do not match Modell Skelette passen nicht zusammen This looks like a player model. Do you want to load all sections? Dies sieht wie Spieler-Modell aus. Wollen sie alle Sektionen laden? Could not load texture Konnte Textur nicht laden Write not supported, try "Export..." Schreiben wird nicht unterstützt, versuchen sie "Exportieren..." Unrecognized file extension (unknown type) Unbekannte Dateierweiterung (unbekannter Typ) MD2 requires all groups to have the same material. MD2 erfordert, dass alle Gruppen das selbe Material haben. MD2 export requires all faces to be grouped. MD2 Export erfordert, dass alle Flächen einer Gruppe zugeordnet sind. MD3 export requires all faces to be grouped. MD3 Export erfordert, dass alle Flächen einer Gruppe zugeordnet sind. MD3_PATH+filename is to long. MD3_PATH+Dateiname ist zu lang. Too many animation frames for MD3 export. Zu viele Animations Frames für MD3 export. Too many points for MD3 export. Zu viele Punkte für MD3 Export. Too many groups for MD3 export. Zu viele Gruppen für MD3 Export. Too many faces in a single group for MD3 export Zu viele Flächen in einzelner Gruppe für MD3 Export Too many vertices in a single group for MD3 export Zu viele Vertizes in einzelner Gruppe für MD3 export Point name is too large for MD3 export. Punkt name ist zu lang für MD3 export. Group name is too large for MD3 export. Gruppen name ist zu lang für MD3 export. Texture filename is too long. Dateiname der Textur ist zu lang. MM3D does not support CAL3D files in XML format MM3D unterstützt keine CAL3D Dateien im XML Format The file does not contain any mesh or animation data Diese Datei enthält keine Mesh- oder Animations- Daten MapDirectionBase Which direction? Welche Richtung? Set new texture coordinates from which direction? Setzte neue Textur Koordinaten von welcher Richtung aus? Front Vorne Back Hinten Left Links Right Rechts Top Oben Bottom Unten Ok Ok Cancel Abbrechen MergeWinBase Merge Model Modelle zusammenfügen Merge location ?Zusammenfügungs Koordinaten 0.0 0.0 Rotation Rotation Translation Translation Merge Options Zusammenfügungs Optionen Include textures Texturen einbeziehen Include animations Animationen einbeziehen Animation Options Animations Optionen Append animations Animationen anhängen Merge if possible Zusammenfügen falls möglich Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen MergeWindow F1 Help Shortcut F1 Merge models operation complete Modelle zusammenfügen MetaWindow F1 Help Shortcut F1 Name meta value key name Name Value meta value 'value' Wert Change meta data operation complete Meta Daten ändern MetaWindowBase Name Name Value Wert Model Meta Data Modell Meta Daten New Neu Delete Löschen Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen ModelViewBase ModelView Modell Ansicht Perspective Perspektive Front Vorne Back Hinten Left Links Right Rechts Top Oben Bottom Unten Orthographic Orthographisch ModelViewport Could not load background %1 Konnte Hintergrund nicht laden %1 Use the middle mouse button to drag/pan the viewport Benutzen Sie den mittleren Mausknopf um die Ansicht zu bewegen OpenGL error = Invalid Value OpenGL Fehler = Ungültiger Wert OpenGL error = Invalid Enum OpenGL Fehler = ungültige Enum OpenGL error = Invalid Operation OpenGL Fehler = ungültige Operation OpenGL error = Stack Overflow OpenGL Fehler = Stack Overflow OpenGL error = Stack Underflow OpenGL Fehler = Stack Underflow OpenGL error = Out Of Memory OpenGL Fehler = Out of Memory OpenGL error = Unknown OpenGL Fehler = Unbekannt Ms3dPrompt F1 Help Shortcut F1 Ms3dPromptBase MS3D Filter Options MS3D Filter Optionen Format Subversion Format Subversion Subversion 0 Subversion 0 Subversion 1 Subversion 1 Subversion 2 Subversion 2 Subversion Options Subversion Optionen Vertex Extra Vertex Extra FFFFFFFF FFFFFFFF Ok Ok Cancel Abbrechen NewAnimBase New Animation Neue Animation &Name &Name Animation Type Animations Typ &Skeletal &Skelet Alt+S Alt+S &Frame &Frame Alt+F Alt+F &Ok &Ok Alt+O Alt+O &Cancel &Abbrechen Alt+C Alt+C ObjPrompt F1 Help Shortcut F1 ObjPromptBase OBJ Filter Options OBJ Filter Optionen &Save normals &Normale speichern Alt+S Alt+S &Normal Decimal Places &?Normale Dezimal Plätze &Texture Decimal Places &?Textur Dezimal Plätze &Vertex Decimal Places &Vertex Dezimal Plätze Ok Ok Cancel Abbrechen PaintTextureWin F1 Help Shortcut F1 File name for saved texture? Dateiname für zu speichernde Textur? File exists. Overwrite? Datei existiert bereits. Überschreiben? Could not write file: Konnte Datei nicht schreiben: PaintTextureWinBase Paint Texture Erstelle Texture Polygons: Polygone: Edges Edges Filled Gefüllte Filled and Edges Gefüllte und Edges Vertices Vertizes Hidden Versteckte Visible Sichtbare Clear Background Lösche Hintergrund Save Size: Größe beim Speichern: 64 64 128 128 256 256 512 512 1024 1024 2048 2048 x x Save Texture... Speichere Textur... Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Close Schließen PluginWinBase Plugin Plugin Version Version Description Beschreibung Status Status Plugins Plugins Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok PluginWindow F1 Help Shortcut F1 PointWin F1 Help Shortcut F1 Rename point window title Punkt umbennen Enter new point name: Neuen Namen für Punkt eingeben: Point changes operation complete Änderungen an Punkten PointWinBase Points Punkte Rename Umbenennen Delete Löschen Bone Joint Knochen Gelenk (none) (kein) F1 for help F1 für Hilfe Ok Ok Cancel Abbrechen PolyToolWidget Poly Type Polygon Typ Strip Triangle strip option Streifen Fan Triangle fan option Fächer ProjToolWidget Type Typ Cylinder Cylinder projection type Zylinder Sphere Sphere projection type Sphäre Plane Plane projection type Ebene ProjectionWin F1 Help Shortcut F1 Set Projection Type operation complete Setze Projektions Typ Set Triangle Projection operation complete Setze Dreiecks Projektion Apply Projection operation complete Wende Projektion an Reset UV Coordinates operation complete Setze UV-Koordinaten zurück Rename projection window title Projektion umbenennen Enter new point name: Namen für neuen Punkt eingeben: Rename Projection operation complete Projektion umbenennen CTRL+Z Undo shortcut STRG+Z CTRL+Y Redo shortcut STRG+Y ProjectionWinBase Texture Projection Textur Projektion Material Material Test Pattern Test Muster Cylinder Zylinder Sphere Sphäre Plane Ebene Show: Zeige: Type: Typ: Rename Umbenennen Zoom: Zoom: 1.0 1.0 Remove Faces Flächen löschen Add Faces to Projection Füge Flächen zu Projektion hinzu Apply Projection Projektion anwenden Reset UV Range Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Close Schließen RgbaWin F1 Help Shortcut F1 RgbaWinBase RGBA Window RGBA Fenster Light Property Light Eigenschaften 0.00 0.00 Red Rot Green Grün Blue Blau Alpha Alpha Close Schließen RotateToolWidget X X Y Y Z Z ScaleToolWidget Proportion Proportionen Free Free scaling option Frei Keep Aspect 2D 2D scaling aspect option Behalte 2D Aspekt bei Keep Aspect 3D 3D scaling aspect option Behalte 3D Aspekt bei Point Punkt Center Scale from center Mitte Far Corner Scale from far corner SelectFaceToolWidget Include Back-facing Rückseiten mit einbeziehen SpherifyWin Spherify operation complete StatusBar V: Vertices status bar label F: Faces status bar label G: Groups status bar label B: Bone Joints status bar label P: Points status bar label M: Materials status bar label StatusBarBase Form1 Status text V:0 F:0 G:0 B:0 P:0 T:0 TextWinBase Text Window Text Fenster Ok Ok TextureCoord Reset coordinates? window title Koordinaten zurücksetzten? Are you sure you want to reset texture coordinates for this group? Sind Sie sicher, dass sie die Texturkoordinaten für diese Gruppe zurücksetzten wollen? Move texture coordinates Bewege Textur Koordinaten F1 Help Shortcut F1 CTRL+Z Undo shortcut STRG+Z CTRL+Y Redo shortcut STRG+Y Select texture coordinates Wähle Textur Koordinaten aus TextureCoordBase Texture Coordinates Textur Koordinaten Zoom: Zoom: 1.0 1.0 Mouse Tool Maus Werkzeug Select Auswählen Move Bewegen Scale Skalieren Scale Options Skalierungs Optionen Scale from center Von Mitte Skalieren Keep aspect ratio Aspekt Rate beibehalten Map Scheme Triangle Dreieck Quad Quadrat Group Gruppe Reset Coordinates Setze Koordinaten zurück Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Close Schließen Rotate Rotieren Lines Linien Black Schwarz Blue Blau Green Grün Cyan Türkis Red Rot Magenta Magenta Yellow Gelb White Weiß Selection Auswahl Rotate CCW Rotiere CCW Rotate CW Rotiere CW V Flip H Flip TextureWindow All Supported Formats ( all texture formats Alle unterstützten Formate ( Open texture image Öffne Textur Could not open file Konnte Datei nicht öffnen Color Material window title Material Farbe Enter new material name: Geben Sie einen neuen Material Namen ein: Rename texture window title Textur umbenennen Enter new texture name: Neuen Textur Namen eingeben: Texture changes Textur Änderungen Shininess Glanz Red Rot Change texture... Change material's texture file Textur ändern... Set texture... Add texture file to material Setze Textur... F1 Help Shortcut F1 TextureWindowBase Materials Materialien None Kein New Material... Neues Material... Rename Umbenennen Delete Löschen Wrap X Clamp X Wrap Y Clamp Y Change Texture... Textur ändern... X X Remove texture Textur entfernen Flat Preview Flache Vorschau 3D Preview 3D Vorschau 0.00 0.00 Alpha Alpha Green Grün Blue Blau Red Rot Ambient Diffuse Diffus Specular Emissive Shininess Glanz Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen Tool Attract Far Attracting far selected primitives Attract far complete Attract Near Attracting near selected primitives Attract near complete Move Background Image Hintergrundbild bewegen Moving background image Bewege Hintergrundbild Cannot move background from 3D view Kann Hintergrund nicht von 3D Ansicht aus bewegen Background move complete Hintergrund bewegen abgeschlossen Move background image Hintergrundbild bewegen Scale Background Image Hintergrundbild skalieren Scaling background image Skaliere Hintergrundbild Cannot scale background from 3D view Kann Hintergrundbild nicht aus 3D Ansicht skalieren Background scale complete Hintergrundbild skalieren abgeschlossen Scale background image Skaliere Hintergrundbild Cube created Würfel erstellt Create Cube Erstelle Würfel Cylinder created Zylinder erstellt Create Cylinder Erstelle Würfel Ellipsoid created Ellipsoid erstellt Create Ellipsoid Erstelle Ellipsoid Joint created Gelenk erstellt Root joint created Wurzelgelenk erstellt Create Bone Joint Erstelle Knochen Gelenk Moving selected primitives Bewege ausgewählte Primitives Move complete Bewegung abgeschlossen Tip: Hold shift to restrict movement to one dimension Tip: Halten Sie [Shift] gedrückt um die Bewegung auf eine Dimension zu beschränken Move Bewegen Point created Punkt erstellt Create Point Erstelle Punkt Create Polygon Erstelle Polygon Projection created Projektion erstellt Create Projection Erstelle Projektion Rectangle created Rechteck erstellt Create Rectangle Erstelle Rechteck Tip: Hold shift to rotate in 15 degree increments Tip: Halten Sie [Shift] gedrückt, um in 15 Grad Schritten zu drehen Rotating selected primitives Rotiere ausgewählte Primitives Setting rotation point Setze Rotationspunkt Rotate complete Rotation komplett Rotate Rotiere Scale Skaliere Scaling selected primitives Skaliere ausgewählte Primitives Scale complete Skalierung komplett Tip: Hold shift to restrict scaling to one dimension Tip: Halten Sie [Shift] gedrückt, um die Skalierung auf eine Dimension zu beschränken Starting selection Beginne Auswahl Selection complete Auswahl komplett Select Bone Joints Wähle Knochen Gelenke aus Select Connected Mesh Wähle zusammenhängendes Mesh aus Select Faces Wähle Flächen aus Select Groups Wähle Gruppen aus Select Points Wähle Punkte aus Select Projections Wähle Projektionen aus Select Vertices Wähle Vertizes aus Shear Starting shear on selected primitives Shear complete Torus created Torus erstellt Create Torus Erstelle Torus Vertex created Vertex erstellt Create Vertex Erstelle Vertex Dragging selected vertex Ziehe ausgewählten Vertex Must a vertex selected Es muss ein Vertex ausgewählt sein Drag complete Ziehen abgeschlossen Drag Vertex on Edge Ziehe Vertex auf Ecke Extrude complete Extrudieren abgeschlossen Extrude Extrudieren Must have faces selected to extrude Es müssen Flächen ausgewählt sein, um zu extrudieren Extruding selected faces Extrudiere ausgewählte Flächen Background Image Hintergrund Bild Create Other Erstelle Andere Select Auswahl Attract Anziehen TorusToolWidget Segments Segmente Sides Seiten Width Breite Circle Kreis From Center Checkbox that indicates if torus is created from center or from far corner von Mitte aus TransformWindow Matrix Translate Matrix Translation Matrix Rotate Matrix Rotation Matrix Rotate On Axis Matrix Rotation auf Achse Matrix Scale Matrix Skalierung Apply Matrix Wende Matrix an Transform Cannot Be Undone window title Transformierung kann nicht Rückgängig gemacht werden This transformation cannot be undone. Diese Transformation kann nicht rückgängig gemacht werden. Are you sure you wish to continue? Sind Sie sicher, dass Sie fortfahren möchten? Apply Transformation button Wende Transformation an Cancel Transformation button Breche Transformation ab F1 Help Shortcut F1 TransformWindowBase Transform Model Transformiere Model 0 0 X X Y Y Z Z Translate Übersetze Euler Angles Eulersche Winkel Rotate Rotiere Quaternion Angle Winkel Axis Achse 1.0 1.0 Scale Skalieren 1 1 (bottom row is translation) (untere Reihe ist Translation) Apply Matrix Wende Matrix an Matrix Matrix Apply to: Wende an auf: Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Close Schließen Selected (including animations) Ausgewählte (inklusive Animationen) Entire Model (including animations) Ganzes Model (inklusive Animationen) ValueWin F1 Help Shortcut F1 ValueWinBase Value Window Werte Fenster Value Wert Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen Ok Ok Cancel Abbrechen ViewWindow Some models are unsaved. Save before exiting? Einige Modelle sind noch nicht gespeichert. Speichern vor Beenden? Press F1 for help using any window Drücken Sie F1 um zur Hilfe für jedes Fenster zu gelangen Properties Eigenschaften New File|New Neu Save File|Save Speichern Run Script... File|Run Script Starte Skript... Recent Scripts File|Recent Script Zuletzt benutzte Skripte Recent Models File|Recent Models Zuletzt benutzte Modelle Plugins... File|Plugins Plugins... Close File|Close Schließen Quit File|Quit Beenden Hide Joints View|Hide Joints Verstecke Gelenke Draw Joint Lines View|Draw Joint Lines Zeichne Gelenk-Linien Draw Joint Bones View|Draw Joint Bones Zeichne Gelenk-Knochen Draw Texture Projections View|Draw Texture Projections Zeichne Textur Projektionen Hide Texture Projections View|Hide Texture Projections Verstecke Textur Projektionen Use Red Error Texture View|Use Red Error Texture Benutze Rote Fehler Textur Use Blank Error Texture View|Use Blank Error Texture Benutze leere Fehler Textur Render 3D Lines View|Render 3D Lines Linien im 3D View mit rendern Hide 3D Lines View|Hide 3D Lines Verstecke Linien im 3D View Draw Back-facing Triangles View|Draw Back-facing Triangles Zeichne Rückseiten von Dreiecken Hide Back-facing Triangles View|Hide Back-facing Triangles Verstecke Rückseiten von Dreiecken Frame All View|Frame Alle Frames Frame Selected View|Frame Ausgewählte Frames Show Properties View|Show Properties Zeige Eigenschaften Render Options View|Render Options Render Optionen 3D Wireframe View|3D 3D Gitter 3D Flat View|3D 3D Flächen 3D Smooth View|3D 3D Geglättet 3D Texture View|3D 3D Texturiert 3D Alpha Blend View|3D 3D mit Alpha Blending Canvas Wireframe View|Canvas Zeichenfläche Gitter Canvas Flat View|Canvas Zeichenfläche Flächen Canvas Smooth View|Canvas Zeichenfläche Geglättet Canvas Texture View|Canvas Zeichenfläche Texturiert Canvas Alpha Blend View|Canvas Zeichenfläche mit Alpha Blending 1 View View|Viewports 1 Ansicht 1x2 View View|Viewports 1x2 Ansicht 2x1 View View|Viewports 2x1 Ansicht 2x2 View View|Viewports 2x2 Ansichten 2x3 View View|Viewports 2x3 Ansichten 3x2 View View|Viewports 3x2 Ansichten 3x3 View View|Viewports 3x3 Ansichten Viewport Settings... View|Viewport Settings Viewport Einstellungen... Grid Tools|Snap to Grid Gitter Vertex Tools|Snap to Vertex Vertex Undo Rückgängig Ctrl+Z Undo shortcut STRG+Z Redo Wiederholen Ctrl+Y Redo shortcut STRG+Y Snap To Schnappe auf Tools Werkzeuge Edit Groups... Groups|Edit Groups Editiere Gruppen... Edit Materials... Groups|Edit Materials Editiere Materialien... Reload Textures Groups|Reload Textures Texuren neu laden Edit Projection... Groups|Edit Projection Editiere Projektion... Edit Texture Coordinates... Groups|Edit Texture Coordinates Editiere Textur Koordinaten... Paint Texture... Groups|Paint Texture Erstelle/Male Textur... Edit Joints... Joints|Edit Joints Editiere Gelenke... Assign Selected to Joint Joints|Assign Selected to Joint Ausgewähltem Gelenk zuweisen Remove All Influences from Selected Joints|Remove All Influences from Selected Alle Einflüsse von Auswahl entfernen Remove Selected Joint from Influencing Joints|Remove Selected Joint from Influencing ?Entferne Ausgewähltes Gelenk von Anliegenden Convert Multiple Influences to Single Joints|Convert Multiple Influences to Single ?Konvertiere Mehrere Einflüsse auf Einzelnen Select Joint Influences Joints|Select Joint Influences ?Wähle Gelenk Einflüsse Select Influenced Vertices Joints|Select Influenced Vertices Wähle beeinflusste Vertizes Select Influenced Points Joints|Select Influenced Points Wähle beeinflusste Punkte Select Unassigned Vertices Joints|Select Unassigned Vertices Wähle nicht-zugewiesene Vertizes Select Unassigned Points Joints|Select Unassigned Points Wähle nicht-zugewiesene Punkte Start Animation Mode... Animation|Start Animation Mode Starte Animationsmodus... Stop Animation Mode Animation|Stop Animation Mode Beende Animationsmodus Animation Sets... Animation|Animation Sets Animations Sets... Copy Animation Frame Animation|Copy Animation Frame Kopiere Animations Frame Paste Animation Frame Animation|Paste Animation Frame Animations Frame einfügen Clear Animation Frame Animation|Clear Animation Frame ?Animationsframe löschen Set Rotation Keyframe Animation|Set Rotation Keyframe Setze Rotations Keyframe Set Translation Keyframe Animation|Set Translation Keyframe Setze Translations Keyframe Contents... Help|Contents Inhalt... License... Help|License Lizenz... About... Help|About Über... &File menu bar &Datei &View menu bar &Ansicht &Tools menu bar &Werkzeuge &Influences menu bar &?Einflüsse &Animation menu bar &Animation &Help menu bar &Hilfe All Files (*) Alle Dateien (*) Save model file as Speichere Model Datei als Open model file Öffne Model Datei Merge models Modelle zusammenfügen : : Script %1 complete Skript %1 komplett Script %1 error %2 Skript %1 Fehler %2 Save first? Zuerst speichern? Model has been modified Do you want to save before closing? Model wurde geändert Wollen Sie speichern bevor sie schließen? Unknown response: %1, Canceling close request Unbekannte Antwort: %1, Abbruch der Close-Anweisung Cannot hide with selected projections. Unselect projections now? Kann nicht mit den ausgewählten Projektionen verstecken. Projektionen de-selektieren? Hide projections Projektionen verstecken Cannot hide with selected joints. Unselect joints now? Kann nicht mit den ausgewählten Geleken verstecken. Gelenke de-selektieren? Hide bone joints Verstecke Knochen Gelenke You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'edit texture coordinates' window Sie müssen zuerst Flächen auswählen. Benutzen sie das 'Wähle Flächen' Werkzeug. You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'paint texture' window Sie müssen zuerst Flächen auswählen. Benutzen sie das 'Wähle Flächen' Werkzeug. Undo %1 Ruckgängig %1 Nothing to undo Es gibt nichts rückgängig zu machen Redo %1 Wiederhole %1 Nothing to redo Es gibt nichts zu wiederholen This model does not have any animations Dieses Model hat keine Animationen Set rotation keframe Setze Rotations Keyframe Set translation keframe Setzte Translations Keyframe Unknown response: Canceling operation Unbekannte Anwort: Breche Operation ab [unnamed] For filename in title bar (if not set) [unbenannt] assigning %1 vertices and %2 points to joints weise %1 Vertizes und %2 Punkte Gelenken zu Assign Selected to Joint Weise Auswahl Gelenk zu You must have at least one bone joint selected. Sie müssen mindestens ein Knochen Gelenk ausgewählt haben. Remove All Influences from Selected ?Entferne alle Einflüsse von Auswahl Remove Joint from Influencing ?Entferne Gelenk von Beeinflussenden Convert To Single Influence ?Konvertiere auf eine Influenz Select Unassigned Vertices Wähle nicht-zugewiesene Vertizes Select Unassigned Points Wähle nicht-zugewiesene Punkte Select Joint Influences ?Wähle Gelenk Einflüsse Select Influences Vertices Wähle beeinflusste Vertizes Select Influenced Points Wähle beeinflusste Punkte Auto-Assign Selected... Joints|Auto-Assign Selected Auswahl Automatisch zuweisen... Auto-Assign Selected to Bone Joints Automatisch Auswahl zu Knochen Gelenken zuweisen You must have at least one vertex or point selected. Sie müssen mindestens einen Vertex oder einen Punkt ausgewählt haben. Open... File|Open Öffnen... Save As... File|Save As Speichern unter... Export... File|Export Exportieren... Edit Model Meta Data... Model|Edit Model Meta Data Editiere Model Meta Daten... Transform Model... Model|Transform Model Transformiere Model... Boolean Operation... Model|Boolean Operation Boolsche Operation... Set Background Image... Model|Set Background Image Setze Hintergrund Bild... Merge... Model|Merge Vereinen... Import Animations... Model|Import Animations Importiere Animationen... Save Animation Images... Animation|Save Animation Images Speichere Animationsbilder... Copy Selected Keyframes Animation|Copy Animation Frame Kopiere Ausgewählte Keyframes Paste Selected Keyframes Animation|Paste Animation Frame Füge Ausgewählte Keyframes ein &Model menu bar &Model &Geometry menu bar &Geometrie Mate&rials menu bar &Materialien All Exportable Formats Alle exportierbaren Formate All Writable Formats Alle schreibbaren Formate Export model Exportiere Model All Supported Formats model formats Alle unterstützten Formate All Supported Formats Alle unterstützten Formate F1 Help Shortcut F1 Export Selected... File|Export Selected Exportiere Auswahl... You must have at least 1 face, joint, or point selected to Export Selected Sie müssen mindestens eine Fläche, Gelenk oder Punkt zum Exportieren Auswählen Clean Up Groups... Groups|Clean Up Groups ViewportSettings F1 Help Shortcut F1 ViewportSettingsBase Viewport Settings Viewport Einstellungen Canvas Grid Zeichenflächen Gitter Default Grid Unit Standard Gitter Einheit 3D Grid 3D Gitter Grid Lines Gitter Linien X/Y Plane X/Y Ebene X/Z Plane X/Z Ebene Y/Z Plane Y/Z Ebene Press F1 for help Drücken Sie F1 um zur Hilfe zu gelangen &Ok &Ok Alt+O Alt+O &Cancel &Abbrechen Alt+C Alt+C Decimal Grid Binary Grid Fixed Grid mm3d-master/i18n/mm3d_fr.ts000066400000000000000000006656451324021725400157130ustar00rootroot00000000000000 AboutWin Misfit Model 3D - About Misfit Model 3D - A Propos AlignWin F1 Help Shortcut F1 Align X Aligner X Align Y Aligner Y Align Z Aligner Z Align Selected operation complete Aligner la selection AlignWinBase Align Selection Aligner la selection Align X Aligner X Align minimum Aligner au minimum Align center Aligner au centre Align maximum Aligner au maximum 0.0 0.0 Align &X Now Aligner &X Maintenant Alt+X Alt+X Align Y Aligner X Align &Y Now Aligner &Y Maintenant Alt+Y Alt+Y Align Z Aligner Z Align &Z Now Aligner &Z Maintenant Alt+Z Alt+Z Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler AnimConvertWinBase Convert To Frame Convertir en pose (Morph Frame) Convert Skeletal to Frame: Convertir Squelette en Pose (Morph frame): AnimName Nom de l'animation Frame Anim Name: Nom de la pose (Morph Frame) de l'animation: Frame Count Nombre de poses (Morph frames) F1 for help Appuyer sur F1 pour l'aide Continue Continuer Cancel Annuler Cancel All Annuler Tout AnimConvertWindow F1 Help Shortcut F1 Convert Skeletal to Frame: Convertir Squelette en Pose (frame): Convert Frame to Frame: Convertir Pose en Pose (frame): Convert Frame Relative to Frame: Convertir Pose Relative en Pose (frame): Convert Unknown Type to Frame: Convertir Type Inconnu en Pose (frame): AnimExportWinBase Export Animation Exporter l'Animation Source Source Animation Animation Viewport Visualisation Duration Durée Iterations Itérations Seconds Secondes Output Sortie Directory Répertoire Format Format anim_0001.jpg anim_0001.jpg anim_1.jpg anim_1.jpg anim_0001.png anim_0001.png anim_1.png anim_1.png ... ... /some/path/name /un/nom/de/chemin 25.0 25.0 Frame Rate Taux d'images par secondes Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler 1 1 15 15 AnimExportWindow Skeletal - Skeletal Animation prefix Squelette - Frame - Frame Animation prefix Pose (Frame) - [None] No viewport for animation image export [Aucun] Viewport %1 - Visualisation %1- F1 Help Shortcut F1 Must have more than 0 frames per second Il est obligatoire d'avoir plus de 0 images par seconde Must have more than 0 seconds of animation Il est obligatoire d'avoir plus de 0 secondes par animation Could not write file: Impossible d'écrire le fichier: Output directory does not exist. Le répertoire destination n'existe pas. AnimSetWinBase Animation Sets Ensemble d'Animation &Down &Bas &Up &Haut &New &Nouveau &Rename &Renommer D&elete &Effacer &Copy &Copier &Split &Séparer &Join &Joindre &Merge &Fusionner Con&vert To Frame Animation Con&vertir en Animation de pose (Frame) Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler AnimSetWindow Skeletal Animation Animation par squelette Frame Animation Animation par pose F1 Help Shortcut F1 Misfit 3D Misfit 3D New name: Nouveau Nom : Split at frame Split animation frame window title Séparer l'animation à cette image Split 'Split' refers to splitting an animation into two separate animations Séparer at frame number the frame number where the second (split) animation begins à l'image numéro Cannot Split Cannot split animation window title Impossible de séparer Must have at least 2 frames to split split animation Il faut avoir 2 images pour découper Cannot merge animation %1 and %2, frame counts differ. Impossible de fusionner l'animation %1 et %2, Le nombre d'images diffère. Can only merge skeletal animations. Ne peut fusionner que les animation par squelette. Animation changes operation complete Changement d'animation copy copier split découper AnimWidget F1 Help Shortcut F1 <New Animation> <Nouvelle Animation> Start animation mode operation complete Entrer en mode Animation New Animation operation complete Nouvelle Animation Frame: Image: Set FPS Frames per second, operation complete Choisir le nombre d'image par secondes Change Frame Count operation complete Changer le nombre d'images Clear frame Remove animation data from frame, operation complete Effacer l'image Paste frame paste frame animation position, operation complete Coller l'image (la pose) Paste keyframe Paste keyframe animation data complete Coller l'image clé (pose clé) End animation mode operation complete Sortir du mode d'animation Frame: n/a Image: n/a Delete Animation? window title Effacer l'animation ? Are you sure you want to delete this animation? Etes vous sûre de vouloir effacer cette animation ? Delete Animation Delete animation, operation complete Effacer l'animation No frame animation data to paste Pas de données d'animation de pose (images) No skeletal animation data to paste Pas de données d'animation de squelette AnimWidgetBase Animation Animation FPS Images Par Seconde Play Jouer Stop Stop Loop Boucle Frames Images Frame: 03 Image: 03 X X Delete Animation Effacer l'animation AnimWindow Animations Animations AutoAssignJointWin F1 Help Shortcut F1 AutoAssignJointWinBase Auto-Assign Bone Joints Assigner automatiquement les joints os Only assign to selected joints Assigner seulement au joints selectionnés Single Simple Multiple Plusieurs Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler BackgroundSelect All Supported Formats ( Tous les formats supportés ( Open background image Ouvrir l'image de fond All Files (*) Tous les fichiers (*) Could not open file Impossible d'ouvrir le fichier BackgroundSelectBase BackgroundSelect Selection du fond None Aucun File... Fichier... BackgroundWin F1 Help Shortcut F1 Background Image operation complete Image de fond BackgroundWinBase Select Background Image Selectionner l'image de fond Front Devant Back Derrière Left Gauche Right Droite Top Haut Bottom Bas Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler BoolPanel Boolean Operation Opération Booléene BoolWin Union boolean operation Union Subtraction boolean operation Soustraction Intersection boolean operation Intersection You must have at least once face selected Au moins une face doit être selectionné Object A triangles are still selected Les triangles de l'objet A sont encore selectionnés Union With Selected boolean operation Union avec la selection Subtract Selected boolean operation Soustraire la selection Intersect With Selected boolean operation Intersection avec la selection Fuse Selected boolean operation Fusionner la selection Select faces to set Select faces to set as 'A' Object in boolean operation Selectionner les faces pour les opérations BoolWinBase Boolean Operation Opération booléene Operation Opération Fuse Fusionner Union Union Subtraction Soustraction Intersection Intersection Set Object A Choisir l'objet A Select faces to set Selectionner les faces à fixer Subtract Selected Soustraire la selection Cal3dPrompt F1 Help Shortcut F1 Cal3dPromptBase Cal3D Filter Options Options du filtre Cal3D Save Meshes Sauvegarder les Meshes All meshes in one file Tous les meshes dans un seul fichier Group meshes by name Grouper les meshes par nom Save Materials Sauver les materiaux CRF (Binary) CRF (binaire) XRF (XML Text) XRF (texte xml) Ok Ok Cancel Annuler Command Align Selected... Aligner la selection... Assigning %1 vertices and %2 points to joint %3 Assigner %1 vertex et %2 points au joint %3 You must have exactly 1 bone joint selected. Vous devez avoir exactement 1 joint d'os selectionné. Assign Selected to Bone Joint Assigner la selection au joint d'os Set Background Image... Fixer l'image de fond... Cap Holes complete Remplissage des trous terminés Could not find gap in selected region Impossible de trouver de trous dans la région selectionné Cap Holes Remplir les trous Selected primitives copied Primitives selectionnées copiées You must have at least 1 face, joint, or point selected to Copy Vous devez avoir au moins 1 face, joint ou point selectionné pour le Copier Copy complete Copie terminée Copy Selected to Clipboard Copier la selection dans le presse-papiers Delete Effacer Deleting joints may destroy skeletal animations Do you wish to continue? Effacer les joins peut détruire des animations de squelette Etes vous sûr de vouloir continuer? Primitives deleted Primitives effacées Selected primitives duplicated Selectionner les primitives dupliquées You must have at least 1 face, joint, or point selected to Duplicate Vous devez avoir au moins 1 face, joint, ou point selectionné à dupliquer Duplicate complete Duplication terminée Duplicate Dupliquer Edge Divide complete Division des bords terminée You must have at 2 adjacent vertices to Edge Divide Vous devez avoir 2 vertex adjacent pour diviser un bord Edge Divide Division de bord Edge Turn complete Tour de bord complet You must have at least 2 adjacent faces to Edge Turn Vous devez avoir 2 vertex adjacent pour tourner un bord Edge Turn Tourner un Bord Extrude... Extrusion... Flatten Aplatir Flatten X Aplatir X Flatten Y Aplatir Y Flatten Z Aplatir Z Need at least 1 vertex, joint, point, or face selected Vous devez avoir au moins 1 face, joint ou point selectionné Selected primitives flattened Primitives selectionnées aplatie Flip Inverser Flip X Inverser X Flip Y Inverser Y Flip Z Inverser Z Selected primitives flipped Primitives selectionnées inversées Hide Cacher Hide Unselected Cacher ce qui n'est pas selectionné Hide Selected Cacher la selection Unhide All Rendre tout visible Selected primitives hidden Selectionner les primitives cachées Primitives unhidden Primitives ré-affichées Unselected primitives hidden Deselectionner les primitives cachées Selection inverted Selection Inversée Invert Selection Inversion de la selection Normals inverted Normals Inversées Invert Normals Inversion des normales Joints... Joints... Make Face From Vertices Construire un Face depuis les vertex Face created Face Crée Must select exactly 3 vertices Il faut selectionner exactement 3 vertex Paste complete Coller terminé Paste from Clipboard Coller depuis le presse-papiers Points... Points... Rotate Texture Coordinates Tourner les Coordonnées de texture Face Face Group Groupe Texture coordinates rotated Coordonnées de texture tournées Must select faces Il faut selectionner des faces Select Free Vertices Selectionner les Vertex Libres Free-floating vertices selected Vertex Libres Flottants Selectionnés Simplify Mesh Simplifier le Mesh (Maillage) Snap Vertices Together Coller les Vertex Ensemble Snap All Selected Coller Ensemble la Selection Snap Nearest Selected Coller au plus proche selectionné Snap All and Weld Coller Ensemble et Souder Snap Nearest and Weld Coller au plus proche et Souder Spherify... Arrondir... Subdivide complete Sousdivision terminée Subdivide Faces Sousdiviser les Faces You must have 1 or more vertices selected to unweld. Vous devez avoir au moins un vertex selectionné pour Défusionner. Unweld Vertices Défusionner les Vertex You must have 2 or more vertices selected to weld. Vous devez avoir au moins 2 vertex selectionné pour fusionner. Weld Vertices Fusionner les Vertex Unwelded %1 vertices into %2 vertices Défusionner %1 vertex en %2 vertex Welded %1 vertices into %2 vertices Fusionner %1 vertex en %2 vertex Normals Face Out Normales Dirigées vers le Faces Extérieures Meshes Meshes (Maillages) Normals Normales Vertices Vertex Faces Faces CommandWidget You are in animation mode, but there are no animations ContextGroup <None> <aucun> <New> <Nouveau> New Group Name of new group, window title Nouveau groupe Enter new group name: Entrer le nom du nouveau groupe: Set Group operation complete Fixer le Groupe Unset Group operation complete Défaire le Groupe Set Material operation complete Fixer le Materiau Set Projection operation complete Fixer la Projection ContextGroupBase Group Group Projection Name Nom de la Projection ... ... Material Name Nom du Materiau Group Material: Matériau du Group: Group Name Nom du Groupe Texture Projection Projection de Texture ContextInfluences <None> <aucun> Change Joint Assignment operation complete Changer le facteur d'influence Change Influence Weight operation complete Changer le coefficient d'influence Change Influence Type operation complete Changer le type d'influence <Mixed> multiple types of bone joint influence <Mélange> Custom bone joint influence Personnalisé Auto bone joint influence Auto Remainder bone joint influence Rappel Auto: %1 Auto: %1 Rem: %1 Rem: %1 ContextInfluencesBase Influences Influences Weight Poids Custom Personnalisé Auto Auto Remaining Restant <None> <aucun> Joint Joint <Mixed> <Mélange> ContextName Rename operation complete Renommer ContextNameBase Name Nom ContextPanel Properties Window title Propriétés ContextPosition Set Position operation complete Choisir la position ContextPositionBase Position Choisir la position Z Z Y Y X X Dimensions ContextProjection Set Projection Type operation complete Choisir le type de projection ContextProjectionBase Projection Projection Projection Type Type de Projection Cylinder Cylindre Sphere Sphère Plane Plan ... ... ContextRotation Set Rotation operation complete Choisir la rotation ContextRotationBase Rotation Rotation Z Z Y Y X X CubeToolWidget Cube Cube Segment Segment CylinderToolWidget Segments Segments Sides Cotés Width Largeur Scale Mise à l'échelle EllipsoidToolWidget Smoothness: Adoucissemment : Faces: Faces: Sphere Sphère From Center Checkbox that indicates if ellipsoid is created from center or far corner Depuis le Centre ErrorObject Success Succès Canceled Annulé Operation not supported for this file type Opération non supportée pour ce type de fichiers Invalid argument (internal error) Argument Invalide (erreur interne) File does not exist Le Fichier est inexistant Permission denied Permission Refusée Could not open file Impossible d'ouvrir le fichier Could not read from file Impossible de lire depuis le fichier File is the wrong type or corrupted Le fichier est soit corrompu soit du mauvais type Unsupported version Version non supporté File contains invalid data Le fichier contient des données invalides Unexpected end of file Fin de fichier innattendue Unknown error Erreur inconnue Could not write file Impossible d'ecrire le fichier This operation is not supported Cette opération n'est pas supportée Write not supported, try "Export..." Ecriture non supportée, essayer "Exporter..." Unrecognized file extension (unknown type) Extension de fichier inconnue (type inconnu) ExtrudeWin F1 Help Shortcut F1 Extrude complete Extrusion Terminée Extrude operation complete Extrusion ExtrudeWinBase Extrude Extrusion Extrude options Options d'extrusions X: X: 0 0 Z: Z: Y: Y: Make Back Faces Fabriquer les Faces Arrières E&xtrude E&xtrusion Press F1 for help Appuyer sur F1 pour l'aide Close Fermer GroupCleanBase Group Clean-up Window Merge identical materials Remove unused materials Merge identical groups Remove unused groups Ok Ok Cancel Annuler GroupCleanWin F1 Help Shortcut Group Clean-up operation complete GroupWinBase Groups Goupes No group Pas de groupe New Nouveau Rename Renommer Delete Effacer Select Faces In Group Selectionner les faces dans le Groupe Unselect Faces In Group Déselectionner les faces dans le Groupe Smoothness: 100 Lissage: 100 Max Angle: 000 Angle Maximum : 000 Faces Faces Assign As Group Assigner comme Groupe Add To Group Ajouter au Groupe Texture Texture No texture Pas de Texture Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler GroupWindow F1 Help Shortcut F1 New group window title Nouveau groupe Enter new group name: Entrer le nom du nouveau groupe: Group name must be between 1 and %1 characters Le nom de groupe doit être entre 1 et %1 caractères Bad group name window title Mauvais nom de groupe Cannot change cannot change group name, window title Changement impossible You cannot change the default group name Impossible de changer le nom de groupe par défaut Smoothness: Adoucissemment : Max Angle: Angle Maximal : Group changes operation complete Changement de groupes HelpWinBase Help Aide Contents Contenu Back Arrière Forward Avant Ok Ok JointWin F1 Help Shortcut F1 Rename joint window title Renommer le joint Enter new joint name: Entrer un nouveau nom de point : Joint changes operation complete Modification de Joints JointWinBase Joints joints Rename Renommer Delete Effacer Selection Selection Select Joint Vertices Selectionner les vertex du joint Select Unassigned Vertices Selectionner les vertex non-assignés Assign Selected to Joint Assigner la selection au joint Add Selected to Joint Ajouter la selection au joint F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler KeyConfig V Select Vertices Tool Shortcut V F Select Faces Tool Shortcut F C Select Connected Mesh Tool Shortcut C G Select Groups Tool Shortcut G B Select Bone Joints Tool Shortcut B T Select Points Tool Shortcut T M Move Tool Shortcut M R Rotate Tool Shortcut R H Hide Unselected Command Shortcut H Shift+H Hide Selected Command Shortcut Shift+H ? Unhide All Command Shortcut ? Delete Delete Command Shortcut Effacer Ctrl+D Duplicate Command Shortcut Ctrl+D Ctrl+C Copy to Clipboard Command Shortcut Ctrl+C Ctrl+V Paste from Clipboard Command Shortcut Ctrl+V Insert Extrude Command Shortcut Insérer Ctrl+W Weld Command Shortcut Ctrl+W Ctrl+N File | New Window Shortcut Ctrl+N Ctrl+O File | Open Shortcut Ctrl+O Ctrl+S File | Save Shortcut Ctrl+S Ctrl+Q File | Quit Shortcut Ctrl+Q Home View | Frame All Shortcut Home (début) Shift+Home View | Frame Selected Shortcut Shift+Home (Début) Ctrl+G Groups | Edit Groups Shortcut Ctrl+G Ctrl+M Groups | Edit Materials Shortcut Ctrl+M Ctrl+E Groups | Edit Texture Coordinates Shortcut Ctrl+E Ctrl+B Joints | Assign Selected Shortcut Ctrl+B Shift+U Unhide All Command Shortcut KeyValueWindowBase Edit Meta Data Editer les meta-données Name Nom Value Valeur Ok Ok Cancel Annuler LicenseWin GNU General Public License Licence Publique Générale GNU LowLevel Cannot delete root joint Impossible d'effacer le joint racine Cannot add or delete because you have frame animations. Try "Merge..." instead. Impossible d'ajouter ou d'effacer puisque vous avez des Animations de Pose. Essayer "Fusionner..." à la place. Success Succès Canceled Annulé Operation not supported for this file type Opération non supportée pour ce type de fichiers Invalid argument (internal error, probably null pointer argument) Paramètre Invalide (Erreur interne, probablement un pointeur nulle) File does not exist Le Fichier est inexistant Permission denied Permission Refusée Could not open file Impossible d'ouvrir le fichier Could not read from file Impossible de lire depuis le fichier File is the wrong type or corrupted Le fichier est soit corrompu soit du mauvais type Unsupported version Version non supporté File contains invalid data Le fichier contient des données invalides Unexpected end of file Fin de fichier innattendue Unknown error Erreur inconnue Invalid error code Code d'erreur Invalide Could not write file Impossible d'ecrire le fichier This operation is not supported Cette opération n'est pas supportée MM3D encountered an unexpected data size problem See Help->About to contact the developers MM3D a rencontré un problème de taille de données inattendue Voir "Aide->A Propos" pour contacter les développeurs Model has a texture that is not powers of 2 Le modèles a une texture qui n'est pas une puissance de 2 Could not load Impossible de charger Model contains no skeletal animations Le modèle ne contient pas de données d'animation de squelette Model skeletons do not match Les squelettes des modèle ne correspondent pas This looks like a player model. Do you want to load all sections? Cela ressemble à un modèle de joueur Voulez-vous charger toutes les sections ? Could not load texture Impossible de charger la texture Write not supported, try "Export..." Ecriture non supportée, essayer "Exporter..." Unrecognized file extension (unknown type) Extension de fichier inconnue (type inconnu) MM3D does not support CAL3D files in XML format The file does not contain any mesh or animation data MD2 requires all groups to have the same material. MD2 export requires all faces to be grouped. MD3 export requires all faces to be grouped. MD3_PATH+filename is to long. Too many animation frames for MD3 export. Too many points for MD3 export. Too many groups for MD3 export. Too many faces in a single group for MD3 export Too many vertices in a single group for MD3 export Point name is too large for MD3 export. Group name is too large for MD3 export. Texture filename is too long. MapDirectionBase Which direction? Quelle direction ? Set new texture coordinates from which direction? Quelle direction pour le nouveau jeu de coordonnées de texture ? Front Devant Back Derrière Left Gauche Right Droite Top Haut Bottom Bas Ok Ok Cancel Annuler MergeWinBase Merge Model Fusionner le modèle Merge location Fusionner les lieux 0.0 0.0 Rotation Rotation Translation Translation Merge Options Options de Fusion Include textures Inclure les textures Include animations Inclure les animations Animation Options Options d'Animation Append animations Ajouter les Animations Merge if possible Fusionner si possible Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler MergeWindow F1 Help Shortcut F1 Raccourcis d'Aide Merge models operation complete Fusionner les modèles Opération Terminée MetaWindow F1 Help Shortcut F1 Name meta value key name Nom Value meta value 'value' Valeur Change meta data operation complete Changer les metadata MetaWindowBase Name Nom Value Valeur Model Meta Data Meta Données du Modèle New Nouveau Delete Effacer Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler ModelViewBase ModelView Vue du Modèle Perspective Perspective Front Devant Back Derrière Left Gauche Right Droite Top Haut Bottom Bas Orthographic Orthographique ModelViewport Could not load background %1 Impossible de charger l'image de fond %1 Use the middle mouse button to drag/pan the viewport Utiliser le boutoun du milieu de la souris pour faire glisser la visualisation OpenGL error = Invalid Value Erreur OpenGL = Valeur Invalide OpenGL error = Invalid Enum Erreur OpenGL = Enumération Invalide OpenGL error = Invalid Operation Erreur OpenGL = Opération Invalide OpenGL error = Stack Overflow Erreur OpenGL = Dépassement de Tas OpenGL error = Stack Underflow Erreur OpenGL = Tas Sous Exploité OpenGL error = Out Of Memory Erreur OpenGL = Plus de mémoire OpenGL error = Unknown Erreur OpenGL = Inconnue Ms3dPrompt F1 Help Shortcut F1 Ms3dPromptBase MS3D Filter Options Options des filtres MS3D Format Subversion Format Subversion Subversion 0 Subversion 0 Subversion 1 Subversion 1 Subversion 2 Subversion 2 Subversion Options Options Subversion Vertex Extra Extra Vertex FFFFFFFF FFFFFFFF Ok Ok Cancel Annuler NewAnimBase New Animation Nouvelle Animation &Name &Nom Animation Type Type d'animation &Skeletal &Squelette Alt+S Alt+S &Frame &Pose Alt+F Atl+F &Ok &Ok Alt+O Alt+O &Cancel &Annuler Alt+C Alt+C ObjPrompt F1 Help Shortcut F1 ObjPromptBase OBJ Filter Options Options du filtre OBJ &Save normals &Sauver les normales Alt+S Alt+S &Normal Decimal Places Position Décimale de la &Normale &Texture Decimal Places Position Décimale de la &Texture &Vertex Decimal Places Position Décimale des &Vertex Ok Ok Cancel Annuler PaintTextureWin F1 Help Shortcut F1 File name for saved texture? Nom de fichier pour les textures sauvegardées? File exists. Overwrite? Le Fichier existe. Ecraser ? Could not write file: Impossible d'écrire le fichier: PaintTextureWinBase Paint Texture Peindre la Texture Polygons: Polygones: Edges Bords Filled Intérieur Filled and Edges Interieurs et Bords Vertices Vertex Hidden Caché Visible Visible Clear Background Effacer l'image de fond Save Size: Sauvegarder la Dimension: 64 64 128 128 256 256 512 512 1024 1024 2048 2048 x x Save Texture... Sauvegarder la texture... Press F1 for help Appuyer sur F1 pour l'aide Close Fermer PluginWinBase Plugin Plugins (greffons) Version Version Description Description Status Statut Plugins Plugins (greffons) Press F1 for help Appuyer sur F1 pour l'aide Ok Ok PluginWindow F1 Help Shortcut F1 PointWin F1 Help Shortcut F1 Rename point window title Renommer le point Enter new point name: Entrer un nouveau nom de point : Point changes operation complete Modification de Point PointWinBase Points Points Rename Renommer Delete Effacer Bone Joint Joints d'Os (none) (Aucun) F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler PolyToolWidget Fan Fan Poly Type Strip Triangle strip option Fan Triangle fan option Fan ProjToolWidget Type Type Cylinder Cylinder projection type Cylindre Sphere Sphere projection type Sphère Plane Plane projection type Plan ProjectionWin F1 Help Shortcut F1 Ctrl+Z Undo Ctrl+Z Ctrl+Y Redo Ctrl+Y Set Projection Type operation complete Choisir le type de projection Set Triangle Projection operation complete Choisir la projection des triangles Apply Projection operation complete Appliquer la projection Reset UV Coordinates operation complete Réinitialisation des coordonnées UV Rename projection window title Renommer la projection Enter new point name: Entrer un nouveau nom de point : Rename Projection operation complete Renommer la projection CTRL+Z Undo shortcut CTRL+Y Redo shortcut ProjectionWinBase Texture Projection Projection de Texture Material Matériau Test Pattern Motif de Test Cylinder Cylindre Sphere Sphère Plane Plan Show: Montrer: Type: Type: Rename Renommer Zoom: Zoom: 1.0 1.0 Remove Faces Enlever les Faces Add Faces to Projection Ajouter les Faces à la Projection Apply Projection Appliquer la projection Reset UV Range Remettre à zéro l'intevalle des UV Press F1 for help Appuyer sur F1 pour l'aide Close Fermer RgbaWin F1 Help Shortcut F1 RgbaWinBase RGBA Window Fenêtre RGBA Light Property Propriété de la Lumière 0.00 0.00 Red Rouge Green Vert Blue Bleu Alpha Alpha Close Fermer RotateToolWidget X X Y Z ScaleToolWidget Proportion Proportion Free Free scaling option Libre Keep Aspect 2D 2D scaling aspect option Garder l'aspect 2D Keep Aspect 3D 3D scaling aspect option Garder l'aspect 3D Point Point Center Scale from center Center Far Corner Scale from far corner Coin éloigné SelectFaceToolWidget Include Back-facing Inclure les faces arrières SpherifyWin Spherify operation complete Arrondir StatusBar V: Vertices status bar label V: F: Faces status bar label F: G: Groups status bar label G: B: Bone Joints status bar label J: P: Points status bar label P: M: Materials status bar label M: StatusBarBase Form1 Formulaire1 Status text Texte de statut V:0 V:0 F:0 F:0 G:0 G:0 B:0 B:0 P:0 P:0 T:0 T:0 TextWinBase Text Window Fenetre de texte Ok Ok TextureCoord Reset coordinates? window title Remettre les coordonnées à zéro ? Are you sure you want to reset texture coordinates for this group? Voulez-vous remettre les coordonnées à zéro pour ce group ? Move texture coordinates Bouger les Coordonnées de texture F1 Help Shortcut CTRL+Z Undo shortcut CTRL+Y Redo shortcut Select texture coordinates TextureCoordBase Texture Coordinates Coordonnées de texture Zoom: Zoom: 1.0 1.0 Mouse Tool Outil de Pointage Select Selectionner Move Bouger Scale Mise à l'échelle Scale Options Options d'échelle Scale from center Mise à l'échelle depuis le centre Keep aspect ratio Garder le ratio de l'aspect Map Scheme Type de projection Triangle Triangle Quad Quad Group Groupe Reset Coordinates Remettre les coordonnées à zéro Press F1 for help Appuyer sur F1 pour l'aide Close Fermer Rotate Rotation Lines Black Blue Bleu Green Vert Cyan Red Rouge Magenta Yellow White Selection Selection Rotate CCW Rotate CW V Flip H Flip TextureWindow All Supported Formats ( all texture formats Tous les formats supportés ( Open texture image Ouvrire l'image de la texture All Files (*) Tous les fichiers (*) Could not open file Impossible d'ouvrir le fichier Color Material window title Matériau de couleur Enter new material name: Entrer un nouveau nom de matériau : Rename texture window title Renommer la texture Enter new texture name: Entrer le nouveau nom de la texture: Texture changes Changements de texture Shininess Brillance Red Rouge Change texture... Change material's texture file Changer de texture... Set texture... Add texture file to material Choisir la texture... F1 Help Shortcut TextureWindowBase Materials Matériaux None Aucun New Material... Nouveau Materiau... Rename Renommer Delete Effacer Wrap X Allonger X Clamp X Borner X Wrap Y Allonger Y Clamp Y Borner Y Change Texture... Changer de Texture... X X Remove texture Enlever la texture Flat Preview Prévisualisation Plate 3D Preview Prévisualisation 3D 0.00 0.00 Alpha Alpha Green Vert Blue Bleu Red Rouge Ambient Ambiant Diffuse Diffuse Specular Speculaire Emissive Emissive Shininess Brillance Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler Tool Attract Far Attraction lointaine Attracting far selected primitives Attire les primitives selectionner de loin Attract far complete Attraction lointaint complète Attract Near Attraction rapprochée Attracting near selected primitives Attraction rapprochée des primitives selectionnées Attract near complete Attraction rapprochée terminées Move Background Image Déplacer l'Image de fond Moving background image Déplace L'image de fond Cannot move background from 3D view Impossible de Déplacer l'image de fond depuis la vue 3D Background move complete Déplacement de l'image de fond terminée Move background image Déplacer l'Image de fond Scale Background Image Mettre à l'echelle l'image de fond Scaling background image Mise à l'echelle l'image de fond Cannot scale background from 3D view Impossible de Mettre à l'Echelle l'image de fond depuis la vue 3D Background scale complete Mise à l'echelle de l'image de fond terminée Scale background image Mettre à l'echelle l'image de fond Cube created Cube crée Create Cube Créer le cube Cylinder created Cylindre crée Create Cylinder Créer le Cylindre Ellipsoid created Ellipsoid crée Create Ellipsoid Créer l'Ellipsoid Joint created Joint crée Root joint created Joint Racine crée Create Bone Joint Créer le Joint d'os Moving selected primitives Bouger les primitives selectionnées Move complete Mouvement Complet Tip: Hold shift to restrict movement to one dimension Astuces: Appuyer sur shift pour restreindre le mouvement à une dimension Move Bouger Point created Point crée Create Point Créer le Point Create Polygon Créer le Polygon Projection created Projection crée Create Projection Créer la Projection Rectangle created Rectange Crée Create Rectangle Créer le Rectange Tip: Hold shift to rotate in 15 degree increments Astuces: Appuyer sur shift pour tourner par incréments de 15 degrés Rotating selected primitives Tourner les primitives selectionnées Setting rotation point Fixe le point de Rotation Rotate complete Rotation Terminée Rotate Tourner Scale Mise à l'échelle Scaling selected primitives Mettre à l'echelle les primitives selectionnées Scale complete Mise à l'echelle terminée Tip: Hold shift to restrict scaling to one dimension Astuces: Appuyer sur shift pour restreindre la mise à l'echelle à une dimension Starting selection Commencement de la selection Selection complete Selection terminée Select Bone Joints Selectionner les Joints d'Os Select Connected Mesh Selectionner les Mesh (maillage) Connectés Select Faces Selectionner les Faces Select Groups Selectionner les Groupes Select Points Selectionner les Points Select Projections Selectionner les Projections Select Vertices Selectionner les Vertex Shear Décaler Starting shear on selected primitives Commencer le décalage sur les Primitives selectionnées Shear complete Décalage Terminé Torus created Torus crée Create Torus Créer le Torus Vertex created Vertex Créer Create Vertex Créer le Vertex Dragging selected vertex Glisser le vertex selectionner Must a vertex selected Un vertex doit être selectionner Drag complete Glisser terminé Drag Vertex on Edge Glisser un Vertex sur un Bord Extrude complete Extrusion Terminée Extrude Extrusion Must have faces selected to extrude Des faces doivent être selectionné pour l'extrusion Extruding selected faces Extrusion des facse selectionnées Background Image Image de fond* Create Other Créer Autre Select Selectionner Attract Attraction TorusToolWidget Segments Segments Sides Cotés Width Largeur Circle Cercle From Center Checkbox that indicates if torus is created from center or from far corner Depuis le Centre TransformWindow Matrix Translate Translation par matrice Matrix Rotate Rotation par matrice Matrix Rotate On Axis Rotation par matrice sur un axe Matrix Scale Agrandissement par matrice Apply Matrix Appliquer la matrice Transform Cannot Be Undone window title La transformation ne peut être annulée This transformation cannot be undone. Cette transformation ne peut être annulée. Are you sure you wish to continue? Etes vous sûr de vouloir continuer ? Apply Transformation button Appliquer la Transformation bouton Cancel Transformation button Annuler la transformation F1 Help Shortcut TransformWindowBase Transform Model Transformer le modèle 0 0 X X Y 1 Z 1 Translate Translation Euler Angles Angles d'Euleur Rotate Rotation Quaternion Quaternion Angle Angle Axis Axe 1.0 1.0 Scale Mise à l'échelle 1 1 (bottom row is translation) (La rangée du bas est la translation) Apply Matrix Applique la Matrice Matrix Matrice Apply to: Appliquer à : Entire Model and Animations Tout le Modèle et Animations Press F1 for help Appuyer sur F1 pour l'aide Close Fermer Selected (including animations) Entire Model (including animations) ValueWin F1 Help Shortcut ValueWinBase Value Window Fenêtre de valeur Value Valeur Press F1 for help Appuyer sur F1 pour l'aide Ok Ok Cancel Annuler ViewWindow Some models are unsaved. Save before exiting? Certains modèles n'ont pas été sauvés. Sauver avant de quitter ? Press F1 for help using any window Appuyer sur F1 pour l'aide quelque soit la fenêtre Animations Animations Properties Propriétés New File|New Nouveau Save File|Save Sauvegarder Run Script... File|Run Script Lancer le Script... Recent Scripts File|Recent Script Scripts Recents Recent Models File|Recent Models Modèles Recents Plugins... File|Plugins Plugins (greffons)... Close File|Close Fermer Quit File|Quit Quitter Hide Joints View|Hide Joints Cacher les Joints Draw Joint Lines View|Draw Joint Lines Dessiner les lignes dse joints Draw Joint Bones View|Draw Joint Bones Dessiner les Os des Joints Draw Texture Projections View|Draw Texture Projections Dessiner les Projections de Texture Hide Texture Projections View|Hide Texture Projections Cacher les Projections de Textures Use Red Error Texture View|Use Red Error Texture Utiliser la Texture Erreur Rouge Use Blank Error Texture View|Use Blank Error Texture Utiliser la Texture Erreur Vide Render 3D Lines View|Render 3D Lines Faire le Rendu des lignes 3D Hide 3D Lines View|Hide 3D Lines Cacher les lignes 3D Draw Back-facing Triangles View|Draw Back-facing Triangles Dessiner les Triangles Arrières (BackFacing) Hide Back-facing Triangles View|Hide Back-facing Triangles Cacher les Triangles Arrières (BackFacing) Frame All View|Frame Toutes les Images Frame Selected View|Frame Image Selectionnée Show Properties View|Show Properties Afficher les Propriétés Render Options View|Render Options Options de Rendu 3D Wireframe View|3D Fil de Fer 3D 3D Flat View|3D 3D Platte 3D Smooth View|3D 3D Adoucie 3D Texture View|3D 3D Texturée 3D Alpha Blend View|3D 3D Composition Alpha Canvas Wireframe View|Canvas Zone de Dessin Fil de Fer Canvas Flat View|Canvas Zone de dessin Platte Canvas Smooth View|Canvas Zone de dessin Adoucie Canvas Texture View|Canvas Zone de dessin Texturée Canvas Alpha Blend View|Canvas Zone de dessin avec Composition de l'alpha 1 View View|Viewports 1 Vue 1x2 View View|Viewports 1x2 Vue 2x1 View View|Viewports 2x1 Vue 2x2 View View|Viewports 2x2 Vue 2x3 View View|Viewports 2x3 Vue 3x2 View View|Viewports 3x2 Vue 3x3 View View|Viewports 3x3 Vue Viewport Settings... View|Viewport Settings Configuration de la Visualisation... Grid Tools|Snap to Grid Grille Vertex Tools|Snap to Vertex Vertex Undo Défaire Ctrl+Z Undo shortcut Ctrl+Z Redo Refaire Ctrl+Y Redo shortcut Ctrl+Y Snap To Caler à Tools Outils Edit Groups... Groups|Edit Groups Editer les Groupes... Edit Materials... Groups|Edit Materials Editer les Matérieaux... Reload Textures Groups|Reload Textures Recharger les Textures Edit Projection... Groups|Edit Projection Editer la Projection... Edit Texture Coordinates... Groups|Edit Texture Coordinates Editer les Coordonnées de texture... Paint Texture... Groups|Paint Texture Peindre la Texture... Edit Joints... Joints|Edit Joints Editer les Joints... Assign Selected to Joint Joints|Assign Selected to Joint Assigner la Selection au Joint Remove All Influences from Selected Joints|Remove All Influences from Selected Enlever toutes les influences de la Selection Remove Selected Joint from Influencing Joints|Remove Selected Joint from Influencing Enlever le joint selectionné de l'influence Convert Multiple Influences to Single Joints|Convert Multiple Influences to Single Convertir de multiples influences en une Seule Select Joint Influences Joints|Select Joint Influences Selectionner les Influences du Joint Select Influenced Vertices Joints|Select Influenced Vertices Selectionner les vertex influencés Select Influenced Points Joints|Select Influenced Points Selectionner les Points influencés Select Unassigned Vertices Joints|Select Unassigned Vertices Selectionner les Vertex Non-assignés Select Unassigned Points Joints|Select Unassigned Points Selectionner les Points non-assignés Start Animation Mode... Animation|Start Animation Mode Entrer en Mode Animation... Stop Animation Mode Animation|Stop Animation Mode Quitter le Mode Animation Animation Sets... Animation|Animation Sets Ensemble d'Animation... Copy Animation Frame Animation|Copy Animation Frame Copier La pose (frame) d'animation Paste Animation Frame Animation|Paste Animation Frame Copier la Pose (Frame) d'Animation Clear Animation Frame Animation|Clear Animation Frame Effacer La Pose (Frame) d'animation Set Rotation Keyframe Animation|Set Rotation Keyframe Fixer l'image clée de Rotation Set Translation Keyframe Animation|Set Translation Keyframe Fixer l'image clée de Translation Contents... Help|Contents Contenu... License... Help|License Licence... About... Help|About A propos... &File menu bar &Fichier &View menu bar &Vue &Tools menu bar &Outils &Influences menu bar &Influences &Animation menu bar &Animation &Help menu bar &Aide All Files (*) Tous les Fichiers (*) Save model file as Sauver le ficher sous File exists. Overwrite? Le Fichier existe. Ecraser ? Open model file Ouvrir le fichier modèle Merge models Fusionner les modèles : : Script %1 complete Script %1 terminée Script %1 error %2 Script %1 erreur %2 Save first? Sauvegarder avant ? Model has been modified Do you want to save before closing? Le modèle a été modifié Voulez vous sauver avant de fermer ? Unknown response: %1, Canceling close request Réponse inconnue : %1, Annulation de la requête de fermeture Hide Properties View|Hide Properties Cacher les Propriétés Cannot hide with selected projections. Unselect projections now? Impossible de cacher avec les projections selectionnées. Deselectionner les projections maintenant ? Hide projections Cacher les projections Cannot hide with selected joints. Unselect joints now? Impossible de cacher avec les joints selectionnés. Deselectionner les joints maintenant ? Hide bone joints Cacher les Joints d'Os You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'edit texture coordinates' window Vous devez selectionner les faces avant. Utiliser l'outil de "Selection des Faces". You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'paint texture' window Vous devez selectionner les faces avant. Utiliser l'outil de "Selection des Faces". Undo %1 Défaire %1 Nothing to undo Rien à défaire Redo %1 Refaire %1 Nothing to redo Rien à refaire This model does not have any animations Ce modèle n'a aucune animation Set rotation keframe Fixer l'image clée de rotation Set translation keframe Fixe l'image clée de translation Unknown response: Canceling operation Réponses inconnues : Annuler l'opération [unnamed] For filename in title bar (if not set) [sans nom] assigning %1 vertices and %2 points to joints Assigner %1 vertex and %2 points au joints Assign Selected to Joint Assigner la selection au joint You must have at least one bone joint selected. Vous devez avoir exactement 1 joint d'os selectionné. Remove All Influences from Selected Enlever toutes les influences de la Selection Remove Joint from Influencing Enlever le joint selectionné de l'influence Convert To Single Influence Convertir de multiples influences en une Seule Select Unassigned Vertices Selectionner les vertex non-assignés Select Unassigned Points Selectionner les Points non-assignés Select Joint Influences Selectionner les Influences du Joint Select Influences Vertices Selectionner les vertex influencés Select Influenced Points Selectionner les Points influencés Auto-Assign Selected... Joints|Auto-Assign Selected Assigner automatiquement la selection... Auto-Assign Selected to Bone Joints Assigner seulement au joints d'os You must have at least one vertex or point selected. Vous devez avoir au moins un vertex ou point selectionné. Open... File|Open Ouvrir... Save As... File|Save As Sauver sous... Export... File|Export Exporter... Edit Model Meta Data... Model|Edit Model Meta Data Editer les meta-données du modèle... Transform Model... Model|Transform Model Transformer le modèle... Boolean Operation... Model|Boolean Operation Opération Booléene... Set Background Image... Model|Set Background Image Fixer l'image de fond... Merge... Model|Merge Fusionner... Import Animations... Model|Import Animations Importer les Animations... Save Animation Images... Animation|Save Animation Images Sauver les images des animations... Copy Selected Keyframes Animation|Copy Animation Frame Copier la selection d'images clées Paste Selected Keyframes Animation|Paste Animation Frame Coller la selection d'images clées &Model menu bar &Modèle &Geometry menu bar &Géometrie Mate&rials menu bar &Matériaux All Exportable Formats Tous les formats exportables All Writable Formats Tous les formats inscriptibles Export model Exporter le modèle All Supported Formats model formats Tous les formats supportés All Supported Formats Tous les formats supportés F1 Help Shortcut Export Selected... File|Export Selected You must have at least 1 face, joint, or point selected to Export Selected Clean Up Groups... Groups|Clean Up Groups ViewportSettings F1 Help Shortcut ViewportSettingsBase Viewport Settings Configuration de la visualisation Canvas Grid Grille de la zone de dessin Default Grid Unit Unité de la grille de défaut 3D Grid Grille 3D Grid Lines Lignes de la Grille X/Y Plane Plan X/Y X/Z Plane Plan X/Z Y/Z Plane Plan Y/Z Press F1 for help Appuyer sur F1 pour l'aide &Ok &Ok Alt+O Alt+O &Cancel &Annuler Alt+C Alt+C Decimal Grid Binary Grid Fixed Grid mm3d-master/i18n/mm3d_ref.ts000066400000000000000000006550721324021725400160510ustar00rootroot00000000000000 AboutWin Misfit Model 3D - About AlignWin F1 Help Shortcut Align X Align Y Align Z Align Selected operation complete AlignWinBase Align Selection Align X Align minimum Align center Align maximum 0.0 Align &X Now Alt+X Align Y Align &Y Now Alt+Y Align Z Align &Z Now Alt+Z Press F1 for help Ok Cancel AnimConvertWinBase Convert To Frame Convert Skeletal to Frame: AnimName Frame Anim Name: Frame Count F1 for help Continue Cancel Cancel All AnimConvertWindow F1 Help Shortcut Convert Skeletal to Frame: Convert Frame to Frame: Convert Frame Relative to Frame: Convert Unknown Type to Frame: AnimExportWinBase Export Animation Source Animation Viewport Duration Iterations Seconds Output Directory Format anim_0001.jpg anim_1.jpg anim_0001.png anim_1.png ... /some/path/name 25.0 Frame Rate Press F1 for help Ok Cancel 1 15 AnimExportWindow Skeletal - Skeletal Animation prefix Frame - Frame Animation prefix [None] No viewport for animation image export Viewport %1 - F1 Help Shortcut Must have more than 0 frames per second Must have more than 0 seconds of animation Could not write file: Output directory does not exist. AnimSetWinBase Animation Sets &Down &Up &New &Rename D&elete &Copy &Split &Join &Merge Con&vert To Frame Animation Press F1 for help Ok Cancel AnimSetWindow Skeletal Animation Frame Animation F1 Help Shortcut Misfit 3D New name: Split at frame Split animation frame window title Split 'Split' refers to splitting an animation into two separate animations at frame number the frame number where the second (split) animation begins Cannot Split Cannot split animation window title Must have at least 2 frames to split split animation Cannot merge animation %1 and %2, frame counts differ. Can only merge skeletal animations. Animation changes operation complete copy split AnimWidget <New Animation> Start animation mode operation complete New Animation operation complete Frame: Set FPS Frames per second, operation complete Change Frame Count operation complete Clear frame Remove animation data from frame, operation complete Paste frame paste frame animation position, operation complete Paste keyframe Paste keyframe animation data complete End animation mode operation complete Frame: n/a Delete Animation? window title Are you sure you want to delete this animation? Delete Animation Delete animation, operation complete No frame animation data to paste No skeletal animation data to paste AnimWidgetBase Animation FPS Play Stop Loop Frames Frame: 03 X Delete Animation AnimWindow Animations AutoAssignJointWin F1 Help Shortcut AutoAssignJointWinBase Auto-Assign Bone Joints Only assign to selected joints Single Multiple Press F1 for help Ok Cancel BackgroundSelect All Supported Formats ( Open background image Could not open file BackgroundSelectBase BackgroundSelect None File... BackgroundWin F1 Help Shortcut Background Image operation complete BackgroundWinBase Select Background Image Front Back Left Right Top Bottom Press F1 for help Ok Cancel BoolPanel Boolean Operation BoolWin Union boolean operation Subtraction boolean operation Intersection boolean operation You must have at least once face selected Object A triangles are still selected Union With Selected boolean operation Subtract Selected boolean operation Intersect With Selected boolean operation Fuse Selected boolean operation Select faces to set Select faces to set as 'A' Object in boolean operation BoolWinBase Boolean Operation Operation Fuse Union Subtraction Intersection Set Object A Select faces to set Subtract Selected Cal3dPrompt F1 Help Shortcut Cal3dPromptBase Cal3D Filter Options Save Meshes All meshes in one file Group meshes by name Save Materials CRF (Binary) XRF (XML Text) Ok Cancel Command Align Selected... Assigning %1 vertices and %2 points to joint %3 You must have exactly 1 bone joint selected. Assign Selected to Bone Joint Set Background Image... Cap Holes complete Could not find gap in selected region Cap Holes Selected primitives copied You must have at least 1 face, joint, or point selected to Copy Copy Selected to Clipboard Delete Deleting joints may destroy skeletal animations Do you wish to continue? Primitives deleted Selected primitives duplicated You must have at least 1 face, joint, or point selected to Duplicate Duplicate complete Duplicate Edge Divide complete You must have at 2 adjacent vertices to Edge Divide Edge Divide Edge Turn complete You must have at least 2 adjacent faces to Edge Turn Edge Turn Extrude... Flatten Flatten X Flatten Y Flatten Z Need at least 1 vertex, joint, point, or face selected Selected primitives flattened Flip Flip X Flip Y Flip Z Selected primitives flipped Hide Hide Unselected Hide Selected Unhide All Selected primitives hidden Primitives unhidden Unselected primitives hidden Selection inverted Invert Selection Normals inverted Invert Normals Joints... Make Face From Vertices Face created Must select exactly 3 vertices Paste complete Paste from Clipboard Points... Rotate Texture Coordinates Face Group Texture coordinates rotated Must select faces Select Free Vertices Free-floating vertices selected Simplify Mesh Snap Vertices Together Snap All Selected Snap Nearest Selected Snap All and Weld Snap Nearest and Weld Spherify... Subdivide complete Subdivide Faces You must have 1 or more vertices selected to unweld. Unweld Vertices You must have 2 or more vertices selected to weld. Weld Vertices Unwelded %1 vertices into %2 vertices Welded %1 vertices into %2 vertices Normals Face Out Meshes Normals Vertices Faces CommandWidget You are in animation mode, but there are no animations ContextGroup <None> <New> New Group Name of new group, window title Enter new group name: Set Group operation complete Unset Group operation complete Set Material operation complete Set Projection operation complete ContextGroupBase Group Projection Name ... Material Name Group Material: Group Name Texture Projection ContextInfluences <None> Change Joint Assignment operation complete Change Influence Weight operation complete Change Influence Type operation complete <Mixed> multiple types of bone joint influence Custom bone joint influence Auto bone joint influence Remainder bone joint influence Auto: %1 Rem: %1 ContextInfluencesBase Influences Weight Custom Auto Remaining <None> Joint <Mixed> ContextName Rename operation complete ContextNameBase Name ContextPanel Properties Window title ContextPosition Set Position operation complete ContextPositionBase Position Z Y X Dimensions ContextProjection Set Projection Type operation complete ContextProjectionBase Projection Projection Type Cylinder Sphere Plane ... ContextRotation Set Rotation operation complete ContextRotationBase Rotation Z Y X CubeToolWidget Cube Segment CylinderToolWidget Segments Sides Width Scale EllipsoidToolWidget Smoothness: Faces: Sphere From Center Checkbox that indicates if ellipsoid is created from center or far corner ErrorObject Success Canceled Operation not supported for this file type Invalid argument (internal error) File does not exist Permission denied Could not open file Could not read from file File is the wrong type or corrupted Unsupported version File contains invalid data Unexpected end of file Unknown error Could not write file This operation is not supported Write not supported, try "Export..." Unrecognized file extension (unknown type) ExtrudeWin F1 Help Shortcut Extrude complete Extrude operation complete ExtrudeWinBase Extrude Extrude options X: 0 Z: Y: Make Back Faces E&xtrude Press F1 for help Close GroupCleanBase Group Clean-up Window Merge identical materials Remove unused materials Merge identical groups Remove unused groups Ok Cancel GroupCleanWin F1 Help Shortcut Group Clean-up operation complete GroupWinBase Groups No group New Rename Delete Select Faces In Group Unselect Faces In Group Smoothness: 100 Max Angle: 000 Faces Assign As Group Add To Group Texture No texture Press F1 for help Ok Cancel GroupWindow F1 Help Shortcut New group window title Enter new group name: Group name must be between 1 and %1 characters Bad group name window title Cannot change cannot change group name, window title You cannot change the default group name Smoothness: Max Angle: Group changes operation complete HelpWinBase Help Contents Back Forward Ok JointWin F1 Help Shortcut Rename joint window title Enter new joint name: Joint changes operation complete JointWinBase Joints Rename Delete Selection Select Joint Vertices Select Unassigned Vertices Assign Selected to Joint Add Selected to Joint F1 for help Ok Cancel KeyConfig V Select Vertices Tool Shortcut F Select Faces Tool Shortcut C Select Connected Mesh Tool Shortcut G Select Groups Tool Shortcut B Select Bone Joints Tool Shortcut T Select Points Tool Shortcut M Move Tool Shortcut R Rotate Tool Shortcut H Hide Unselected Command Shortcut Shift+H Hide Selected Command Shortcut Delete Delete Command Shortcut Ctrl+D Duplicate Command Shortcut Ctrl+C Copy to Clipboard Command Shortcut Ctrl+V Paste from Clipboard Command Shortcut Insert Extrude Command Shortcut Ctrl+W Weld Command Shortcut Ctrl+N File | New Window Shortcut Ctrl+O File | Open Shortcut Ctrl+S File | Save Shortcut Ctrl+Q File | Quit Shortcut Home View | Frame All Shortcut Shift+Home View | Frame Selected Shortcut Ctrl+G Groups | Edit Groups Shortcut Ctrl+M Groups | Edit Materials Shortcut Ctrl+E Groups | Edit Texture Coordinates Shortcut Ctrl+B Joints | Assign Selected Shortcut Shift+U Unhide All Command Shortcut KeyValueWindowBase Edit Meta Data Name Value Ok Cancel LicenseWin GNU General Public License LowLevel Cannot delete root joint Cannot add or delete because you have frame animations. Try "Merge..." instead. Success Canceled Operation not supported for this file type Invalid argument (internal error, probably null pointer argument) File does not exist Permission denied Could not open file Could not read from file File is the wrong type or corrupted Unsupported version File contains invalid data Unexpected end of file Unknown error Invalid error code Could not write file This operation is not supported MM3D encountered an unexpected data size problem See Help->About to contact the developers Model has a texture that is not powers of 2 Could not load Model contains no skeletal animations Model skeletons do not match This looks like a player model. Do you want to load all sections? Could not load texture Write not supported, try "Export..." Unrecognized file extension (unknown type) MD2 requires all groups to have the same material. MD2 export requires all faces to be grouped. MD3 export requires all faces to be grouped. MD3_PATH+filename is to long. Too many animation frames for MD3 export. Too many points for MD3 export. Too many groups for MD3 export. Too many faces in a single group for MD3 export Too many vertices in a single group for MD3 export Point name is too large for MD3 export. Group name is too large for MD3 export. Texture filename is too long. MM3D does not support CAL3D files in XML format The file does not contain any mesh or animation data MapDirectionBase Which direction? Set new texture coordinates from which direction? Front Back Left Right Top Bottom Ok Cancel MergeWinBase Merge Model Merge location 0.0 Rotation Translation Merge Options Include textures Include animations Animation Options Append animations Merge if possible Press F1 for help Ok Cancel MergeWindow F1 Help Shortcut Merge models operation complete MetaWindow F1 Help Shortcut Name meta value key name Value meta value 'value' Change meta data operation complete MetaWindowBase Name Value Model Meta Data New Delete Press F1 for help Ok Cancel ModelViewBase ModelView Perspective Front Back Left Right Top Bottom Orthographic ModelViewport Could not load background %1 Use the middle mouse button to drag/pan the viewport OpenGL error = Invalid Value OpenGL error = Invalid Enum OpenGL error = Invalid Operation OpenGL error = Stack Overflow OpenGL error = Stack Underflow OpenGL error = Out Of Memory OpenGL error = Unknown Ms3dPrompt F1 Help Shortcut Ms3dPromptBase MS3D Filter Options Format Subversion Subversion 0 Subversion 1 Subversion 2 Subversion Options Vertex Extra FFFFFFFF Ok Cancel NewAnimBase New Animation &Name Animation Type &Skeletal Alt+S &Frame Alt+F &Ok Alt+O &Cancel Alt+C ObjPrompt F1 Help Shortcut ObjPromptBase OBJ Filter Options &Save normals Alt+S &Normal Decimal Places &Texture Decimal Places &Vertex Decimal Places Ok Cancel PaintTextureWin F1 Help Shortcut File name for saved texture? File exists. Overwrite? Could not write file: PaintTextureWinBase Paint Texture Polygons: Edges Filled Filled and Edges Vertices Hidden Visible Clear Background Save Size: 64 128 256 512 1024 2048 x Save Texture... Press F1 for help Close PluginWinBase Plugin Version Description Status Plugins Press F1 for help Ok PluginWindow F1 Help Shortcut PointWin F1 Help Shortcut Rename point window title Enter new point name: Point changes operation complete PointWinBase Points Rename Delete Bone Joint (none) F1 for help Ok Cancel PolyToolWidget Poly Type Strip Triangle strip option Fan Triangle fan option ProjToolWidget Type Cylinder Cylinder projection type Sphere Sphere projection type Plane Plane projection type ProjectionWin F1 Help Shortcut Set Projection Type operation complete Set Triangle Projection operation complete Apply Projection operation complete Reset UV Coordinates operation complete Rename projection window title Enter new point name: Rename Projection operation complete CTRL+Z Undo shortcut CTRL+Y Redo shortcut ProjectionWinBase Texture Projection Material Test Pattern Cylinder Sphere Plane Show: Type: Rename Zoom: 1.0 Remove Faces Add Faces to Projection Apply Projection Reset UV Range Press F1 for help Close RgbaWin F1 Help Shortcut RgbaWinBase RGBA Window Light Property 0.00 Red Green Blue Alpha Close RotateToolWidget X Y Z ScaleToolWidget Proportion Free Free scaling option Keep Aspect 2D 2D scaling aspect option Keep Aspect 3D 3D scaling aspect option Point Center Scale from center Far Corner Scale from far corner SelectFaceToolWidget Include Back-facing SpherifyWin Spherify operation complete StatusBar V: Vertices status bar label F: Faces status bar label G: Groups status bar label B: Bone Joints status bar label P: Points status bar label M: Materials status bar label StatusBarBase Form1 Status text V:0 F:0 G:0 B:0 P:0 T:0 TextWinBase Text Window Ok TextureCoord Reset coordinates? window title Are you sure you want to reset texture coordinates for this group? Move texture coordinates F1 Help Shortcut CTRL+Z Undo shortcut CTRL+Y Redo shortcut Select texture coordinates TextureCoordBase Texture Coordinates Zoom: 1.0 Mouse Tool Select Move Scale Scale Options Scale from center Keep aspect ratio Map Scheme Triangle Quad Group Reset Coordinates Press F1 for help Close Rotate Lines Black Blue Green Cyan Red Magenta Yellow White Selection Rotate CCW Rotate CW V Flip H Flip TextureWindow All Supported Formats ( all texture formats Open texture image Could not open file Color Material window title Enter new material name: Rename texture window title Enter new texture name: Texture changes Shininess Red Change texture... Change material's texture file Set texture... Add texture file to material F1 Help Shortcut TextureWindowBase Materials None New Material... Rename Delete Wrap X Clamp X Wrap Y Clamp Y Change Texture... X Remove texture Flat Preview 3D Preview 0.00 Alpha Green Blue Red Ambient Diffuse Specular Emissive Shininess Press F1 for help Ok Cancel Tool Attract Far Attracting far selected primitives Attract far complete Attract Near Attracting near selected primitives Attract near complete Move Background Image Moving background image Cannot move background from 3D view Background move complete Move background image Scale Background Image Scaling background image Cannot scale background from 3D view Background scale complete Scale background image Cube created Create Cube Cylinder created Create Cylinder Ellipsoid created Create Ellipsoid Joint created Root joint created Create Bone Joint Moving selected primitives Move complete Tip: Hold shift to restrict movement to one dimension Move Point created Create Point Create Polygon Projection created Create Projection Rectangle created Create Rectangle Tip: Hold shift to rotate in 15 degree increments Rotating selected primitives Setting rotation point Rotate complete Rotate Scale Scaling selected primitives Scale complete Tip: Hold shift to restrict scaling to one dimension Starting selection Selection complete Select Bone Joints Select Connected Mesh Select Faces Select Groups Select Points Select Projections Select Vertices Shear Starting shear on selected primitives Shear complete Torus created Create Torus Vertex created Create Vertex Dragging selected vertex Must a vertex selected Drag complete Drag Vertex on Edge Extrude complete Extrude Must have faces selected to extrude Extruding selected faces Background Image Create Other Select Attract TorusToolWidget Segments Sides Width Circle From Center Checkbox that indicates if torus is created from center or from far corner TransformWindow Matrix Translate Matrix Rotate Matrix Rotate On Axis Matrix Scale Apply Matrix Transform Cannot Be Undone window title This transformation cannot be undone. Are you sure you wish to continue? Apply Transformation button Cancel Transformation button F1 Help Shortcut TransformWindowBase Transform Model 0 X Y Z Translate Euler Angles Rotate Quaternion Angle Axis 1.0 Scale 1 (bottom row is translation) Apply Matrix Matrix Apply to: Press F1 for help Close Selected (including animations) Entire Model (including animations) ValueWin F1 Help Shortcut ValueWinBase Value Window Value Press F1 for help Ok Cancel ViewWindow Some models are unsaved. Save before exiting? Press F1 for help using any window Properties New File|New Save File|Save Run Script... File|Run Script Recent Scripts File|Recent Script Recent Models File|Recent Models Plugins... File|Plugins Close File|Close Quit File|Quit Hide Joints View|Hide Joints Draw Joint Lines View|Draw Joint Lines Draw Joint Bones View|Draw Joint Bones Draw Texture Projections View|Draw Texture Projections Hide Texture Projections View|Hide Texture Projections Use Red Error Texture View|Use Red Error Texture Use Blank Error Texture View|Use Blank Error Texture Render 3D Lines View|Render 3D Lines Hide 3D Lines View|Hide 3D Lines Draw Back-facing Triangles View|Draw Back-facing Triangles Hide Back-facing Triangles View|Hide Back-facing Triangles Frame All View|Frame Frame Selected View|Frame Show Properties View|Show Properties Render Options View|Render Options 3D Wireframe View|3D 3D Flat View|3D 3D Smooth View|3D 3D Texture View|3D 3D Alpha Blend View|3D Canvas Wireframe View|Canvas Canvas Flat View|Canvas Canvas Smooth View|Canvas Canvas Texture View|Canvas Canvas Alpha Blend View|Canvas 1 View View|Viewports 1x2 View View|Viewports 2x1 View View|Viewports 2x2 View View|Viewports 2x3 View View|Viewports 3x2 View View|Viewports 3x3 View View|Viewports Viewport Settings... View|Viewport Settings Grid Tools|Snap to Grid Vertex Tools|Snap to Vertex Undo Ctrl+Z Undo shortcut Redo Ctrl+Y Redo shortcut Snap To Tools Edit Groups... Groups|Edit Groups Edit Materials... Groups|Edit Materials Reload Textures Groups|Reload Textures Edit Projection... Groups|Edit Projection Edit Texture Coordinates... Groups|Edit Texture Coordinates Paint Texture... Groups|Paint Texture Edit Joints... Joints|Edit Joints Assign Selected to Joint Joints|Assign Selected to Joint Remove All Influences from Selected Joints|Remove All Influences from Selected Remove Selected Joint from Influencing Joints|Remove Selected Joint from Influencing Convert Multiple Influences to Single Joints|Convert Multiple Influences to Single Select Joint Influences Joints|Select Joint Influences Select Influenced Vertices Joints|Select Influenced Vertices Select Influenced Points Joints|Select Influenced Points Select Unassigned Vertices Joints|Select Unassigned Vertices Select Unassigned Points Joints|Select Unassigned Points Start Animation Mode... Animation|Start Animation Mode Stop Animation Mode Animation|Stop Animation Mode Animation Sets... Animation|Animation Sets Copy Animation Frame Animation|Copy Animation Frame Paste Animation Frame Animation|Paste Animation Frame Clear Animation Frame Animation|Clear Animation Frame Set Rotation Keyframe Animation|Set Rotation Keyframe Set Translation Keyframe Animation|Set Translation Keyframe Contents... Help|Contents License... Help|License About... Help|About &File menu bar &View menu bar &Tools menu bar &Influences menu bar &Animation menu bar &Help menu bar All Files (*) Save model file as Open model file Merge models : Script %1 complete Script %1 error %2 Save first? Model has been modified Do you want to save before closing? Unknown response: %1, Canceling close request Cannot hide with selected projections. Unselect projections now? Hide projections Cannot hide with selected joints. Unselect joints now? Hide bone joints You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'edit texture coordinates' window You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'paint texture' window Undo %1 Nothing to undo Redo %1 Nothing to redo This model does not have any animations Set rotation keframe Set translation keframe Unknown response: Canceling operation [unnamed] For filename in title bar (if not set) assigning %1 vertices and %2 points to joints Assign Selected to Joint You must have at least one bone joint selected. Remove All Influences from Selected Remove Joint from Influencing Convert To Single Influence Select Unassigned Vertices Select Unassigned Points Select Joint Influences Select Influences Vertices Select Influenced Points Auto-Assign Selected... Joints|Auto-Assign Selected Auto-Assign Selected to Bone Joints You must have at least one vertex or point selected. Open... File|Open Save As... File|Save As Export... File|Export Edit Model Meta Data... Model|Edit Model Meta Data Transform Model... Model|Transform Model Boolean Operation... Model|Boolean Operation Set Background Image... Model|Set Background Image Merge... Model|Merge Import Animations... Model|Import Animations Save Animation Images... Animation|Save Animation Images Copy Selected Keyframes Animation|Copy Animation Frame Paste Selected Keyframes Animation|Paste Animation Frame &Model menu bar &Geometry menu bar Mate&rials menu bar All Exportable Formats All Writable Formats Export model All Supported Formats model formats All Supported Formats F1 Help Shortcut Export Selected... File|Export Selected You must have at least 1 face, joint, or point selected to Export Selected Clean Up Groups... Groups|Clean Up Groups ViewportSettings F1 Help Shortcut ViewportSettingsBase Viewport Settings Canvas Grid Default Grid Unit 3D Grid Grid Lines X/Y Plane X/Z Plane Y/Z Plane Press F1 for help &Ok Alt+O &Cancel Alt+C Decimal Grid Binary Grid Fixed Grid mm3d-master/i18n/mm3d_sk.ts000066400000000000000000006767231324021725400157200ustar00rootroot00000000000000 AboutWin Misfit Model 3D - About Misfit Model 3D - O programe AlignWin F1 Help Shortcut F1 Align X Zarovnať X Align Y Zarovnať Y Align Z Zarovnať Z Align Selected operation complete Zarovnať Označené AlignWinBase Align Selection Zarovnať výber Align X Zarovnať X Align minimum Zarovnať minimum Align center Zarovnať stred Align maximum Zarovnať maximum 0.0 0.0 Align &X Now Zarovnať &X Teraz Alt+X Alt+X Align Y Zarovnať Y Align &Y Now Zarovnať &Y Teraz Alt+Y Alt+Y Align Z Zarovnať Z Align &Z Now Zarovnať &Z Teraz Alt+Z Alt+Z Press F1 for help Stlač F1 pre pomoc Ok Ok Cancel Zrušiť AnimConvertWinBase Convert To Frame Konvertovať na rámec Convert Skeletal to Frame: Konvertovať kostrovú na rámcovú: AnimName AnimName Frame Anim Name: Názov rámcovej animácie: Frame Count Počet rámcov F1 for help Stlač F1 pre pomoc Continue Pokračovať Cancel Zrušiť Cancel All Zrušiť všetko AnimConvertWindow F1 Help Shortcut F1 Convert Skeletal to Frame: Konvertovať kostrovú na rámcovú: Convert Frame to Frame: Konvertovať rámcovú na rámcovú: Convert Frame Relative to Frame: Konvertovať rámcovú relatívnu na rámcovú: Convert Unknown Type to Frame: Konvertovať neznámy typ na rámec: AnimExportWinBase Save Animation Images Export animácie Source Zdroj Animation Animácia Viewport Výrez Duration Trvanie Iterations Cykly Seconds Sekúnd Output Výstup Directory Adresár Format Formát anim_0001.jpg anim_1.jpg anim_0001.png anim_1.png ... ... /some/path/name /sem/nejaku/cestu/ 25.0 Frame Rate Rámcov za sekundu Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť Export Animation Export animácie 1 15 AnimExportWindow Skeletal - Skeletal Animation prefix Kostrová - Frame - Frame Animation prefix Rámec - [None] No viewport for animation image export [Nie je] Viewport %1 - Výrez %1 - F1 Help Shortcut Must have more than 0 frames per second Musí mať viac ako 0 rámcov za sekundu Must have more than 0 seconds of animation Animácia musí mať viac ako 0 sekúnd Could not write file: Nemôžem zapísať súbor: Output directory does not exist. Výstupný adresár neexistuje. AnimSetWinBase Animation Sets Množina animácií &Down &Dole &Up &Hore &New &Nový &Rename &Premenuj D&elete &Vymazať &Copy &Kopírovať &Split &Rozdeľ &Join &Spojiť &Merge &Zlúčiť Con&vert To Frame Animation Kon&vertovať na rámcovú animáciu Press F1 for help Stlač F1 pre pomoc Ok Ok Cancel Zrušiť AnimSetWindow Skeletal Animation Kostrová animácia Frame Animation Rámcová animácia F1 Help Shortcut Misfit 3D New name: Nové meno: Split at frame Split animation frame window title Rozdeľ na rámeci Split 'Split' refers to splitting an animation into two separate animations Rozdeľ at frame number the frame number where the second (split) animation begins za rámcom číslo split rozdeľ Cannot Split Cannot split animation window title Nemôžem rozdeliť Must have at least 2 frames to split split animation Na rozdelenie treba najmenej 2 rámce Cannot merge animation %1 and %2, frame counts differ. Nemôžem zlúčiť animáciu %1 a %2, počet rámcov sa líši. Can only merge skeletal animations. Môžem zlučovať iba kostrové animácie. Animation changes operation complete Zmeny animácie copy kopírovať AnimWidget <New Animation> <Nová animácia> Start animation mode operation complete Spusti režim animácie New Animation operation complete Nová animácia Frame: Rámec: Set FPS Frames per second, operation complete Nastav FPS Change Frame Count operation complete Zmeniť počet rámcov Clear frame Remove animation data from frame, operation complete Vymazať rámec Paste frame paste frame animation position, operation complete Vložiť rámec Paste keyframe Paste keyframe animation data complete Vložiť kľúčový rámec End animation mode operation complete Ukončiť režim animácie Frame: n/a Rámec: nie je Delete Animation? window title Vymazať animáciu? Are you sure you want to delete this animation? Naozaj vymazať túto animáciu? Delete Animation Delete animation, operation complete Vymazať animáciu No frame animation data to paste V schránke nie sú dáta rámcovej animácie No skeletal animation data to paste V schránke nie sú dáta kostrovej animácie AnimWidgetBase Animation Animácia FPS Play Spustiť Stop Zastaviť Loop Slučka Frames Rámce Frame: 03 Rámec: 03 X Delete Animation Vymazať animáciu AnimWinBase Animation Animácia New Nový Rename Premenovať Delete Vymazať Keyframe Kľúčový rámec Frames Rámce Frame: 03 Rámec: 03 Copy Frame Kopírovať Paste Frame Vložiť rámec Clear Frame Výmazať rámec Skeletal Kostrová Frame Rámec Play Spustiť Stop Zastaviť Loop Slučka Press F1 for help Stlač F1 pre pomoc Close Zatvoriť AnimWindow Misfit 3D Misfit 3D New name: Nové meno: Animations Animácie AutoAssignJointWin F1 Help Shortcut AutoAssignJointWinBase Auto-Assign Bone Joints Automaticky priradiť kĺby Only assign to selected joints Iba priradiť k zvoleným kĺbom Single Jeden Multiple Viac Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť BackgroundSelect All Supported Formats ( Všetky podporované formáty ( Open background image Otvoriť obrázok pozadia All Files (*) Všetky súbory (*) Could not open file Namôžem otvoriť súbor BackgroundSelectBase BackgroundSelect None Nič File... Súbor... BackgroundWin F1 Help Shortcut Background Image operation complete Obrázok pozadia BackgroundWinBase Select Background Image Zvoliť obrázok pozadia Front Predok Back Zozadu Left V ľavo Right V pravo Top Vrch Bottom Spodok Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť BoolPanel Boolean Operation Booleovské operácie BoolWin Union boolean operation Zjednotenie Subtraction boolean operation Odčítanie Intersection boolean operation Prienik You must have at least once face selected Musíte zvoliť aspoň jednu plochu Object A triangles are still selected Trojúholníky objektu A sú stále vybrané Union With Selected boolean operation Zjednotiť s vybranými Subtract Selected boolean operation Odčítať zvolené Intersect With Selected boolean operation Prienik so zvolenými Fuse Selected boolean operation Spojiť vybrané Select faces to set Select faces to set as 'A' Object in boolean operation Vybrať plochy do množiny BoolWinBase Boolean Operation Boolovské operácie Operation Operácia Fuse Spojiť Union Zjednotenie Subtraction Odčítať Intersection Prienik Set Object A Nastaviť objekt A Select faces to set Vybrať plochy do množiny Subtract Selected Odčítať zvolené Cal3dPrompt F1 Help Shortcut Cal3dPromptBase Cal3D Filter Options Nastavenia Cal3D filtra Save Meshes Uložiť mriežky All meshes in one file Všetky mriežky v jednom súbore Group meshes by name Zoskupiť mriežky podľa mena Save Materials Uložiť materiály CRF (Binary) CRF (Binárny) XRF (XML Text) XRF (XML Text) Ok Ok Cancel Zrušiť Command Align Selected... Zarovnať označené... Assigning %1 vertices and %2 points to joint %3 Priradujem %1 vrcholov a %2 bodov ku kĺbu %3 You must have exactly 1 bone joint selected. Musíte zvoliť práve 1 bod kostry. Assign Selected to Bone Joint Priradiť označené ku kĺbu kosti Set Background Image... Nastaviť obrázok pozadia... Cap Holes complete Povrchové dierky ukončené Could not find gap in selected region Neviem nájsť otvor vo zvolenej oblasti Cap Holes Povrchové dierky Selected primitives copied Zvolené útvary zkopírované You must have at least 1 face, joint, or point selected to Copy Musíte zvoliť najmenej 1 plochu, uzol alebo bod na Kopírovanie Copy complete Kopírovanie ukončené Copy Selected to Clipboard Kopírovať označené do schránky Delete Vymazať Deleting joints may destroy skeletal animations Do you wish to continue? Vymazanie kĺbov môže zničiť kostrovú animáciu Chcete pokračovať? Primitives deleted Útvary vymazané Selected primitives duplicated Zvolené útvary zdvojené You must have at least 1 face, joint, or point selected to Duplicate Musíte zvoliť najmenej 1 plochu, uzol alebo bod na Duplikovanie Duplicate complete Zdvojenie ukončené Duplicate Zdvojiť Edge Divide complete Rozdelenie okraja dokončené You must have at 2 adjacent vertices to Edge Divide Musíte zvoliť najmenej 2 susedné vrcholy na Rozdelenie plochy Edge Divide Rozdeliť okraj Edge Turn complete Rotovanie okraja dokončené You must have at least 2 adjacent faces to Edge Turn Musíte zvoliť najmenej 2 susedné plochy na vykonanie Rotácie okraja Edge Turn Rotovať okraj Extrude... Vysunúť... Flatten Sploštiť Flatten X Sploštiť X Flatten Y Sploštiť Y Flatten Z Sploštiť Z Need at least 1 vertex, joint, point, or face selected Musíte zvoliť aspoň 1 vrchol, kĺb, alebo plochu Selected primitives flattened Zvolené útvary sploštené Flip Preklopiť Flip X Preklopiť X Flip Y Preklopiť Y Flip Z Preklopiť Z Selected primitives flipped Zvolené útvary otočené Hide Schovať Hide Unselected Schovať nezvolené Hide Selected Schovať zvolené Unhide All Odkryť všetko Selected primitives hidden Zvolené útvary schované Primitives unhidden Útvary odkryté Unselected primitives hidden Odznačiť skrýté útvary Selection inverted Invertovať výber Invert Selection Invertovať označenie Normals inverted Normály invertované Invert Normals Invertovať normály Joints... Kĺby... Make Face From Vertices Vytvoriť plochy z vrcholov Face created Plocha vytvorená Must select exactly 3 vertices Musíte zvoliť práve 3 plochy Paste complete Vloženie dokončené Paste from Clipboard Vložiť zo schránky Points... Body... Rotate Texture Coordinates Otočiť súradnice textúry Face Plocha Group Skupina Texture coordinates rotated Rotovať súradnice textúry Must select faces Musíte zvoliť plochy Select Free Vertices Zvoliť voľné vrcholy Free-floating vertices selected Voľne plávajúce vrcholy zvolené Simplify Mesh Zjednodušiť mriežku Snap Vertices Together Prichytiť vrcholy dokopy Snap All Selected Prichytiť všetky zvolené Snap Nearest Selected Prichytiť najbližšie zvolené Snap All and Weld Prichytiť a spojiť všetko Snap Nearest and Weld Prichytiť najbližšie a spojiť Spherify... Zaguľatiť... Subdivide complete Rozdelenie plôch dokončené Subdivide Faces Ďalej rozdeliť plochy You must have 1 or more vertices selected to unweld. Musíte zvoliť 1 alebo viac vrcholov na Rozdelenie vrcholov. Unweld Vertices Rozdeliť vrcholy You must have 2 or more vertices selected to weld. Musíte mat 2 alebo viac vrcholov na Spojenie vrcholov. Weld Vertices Spojit vrcholy Unwelded %1 vertices into %2 vertices Rozdelené %1 vrcholov na %2 vrcholov Welded %1 vertices into %2 vertices Spojené %1 vrcholov do %2 vrcholov Normals face out Normálami von Vertices Vrcholy Faces Plochy Meshes Mriežky Normals Normály Normals Face Out Normálami von CommandWidget You are in animation mode, but there are no animations Ste v režime animácie, ale nie sú tu žiadne animácie ContextGroup <None> <Žiadne> <New> <Nové> New Group Name of new group, window title Nová skupina Enter new group name: Zadaj meno novej skupiny: Set Group operation complete Nastaviť skupiny Unset Group operation complete Odobrať skupinu Set Material operation complete Nastaviť materiál Set Projection operation complete Nastaviť premietanie ContextGroupBase Group Skupina Projection Name Meno premietania ... ... Material Name Meno materiálu Group Material: Materiál skupiny: Group Name Meno skupiny Triangle Projection Trojúholníkové premietanie Texture Projection Premietanie textúry ContextInfluences <None> <Nič> Change Joint Assignment operation complete Zmeniť priradenie kĺbu Change Influence Weight operation complete Zmeniť pôsobenie hmotnosti Change Influence Type operation complete Zmeniť typ pôsobenia <Mixed> multiple types of bone joint influence <Rôzne> Custom bone joint influence Rôzne Auto bone joint influence Automaticky Remainder bone joint influence Zvyšok Auto: %1 Automaticky: %1 Rem: %1 Ešte: %1 ContextInfluencesBase Influences Pôsobenie Weight Hmotnosť <Mixed> <Zmiešané> Custom Rôzne Auto Automaticky Remaining Zostávajúce <None> <Žiadne> Joint Kĺb ContextName Rename operation complete Premenovať ContextNameBase Name Meno ContextPanel Properties Window title Vlastnosti ContextPosition Set Position operation complete Nastaviť polohu ContextPositionBase Position Poloha Z Y X Dimensions Rozmery ContextProjection Set Projection Type operation complete Nastaviť typ zobrazenia ContextProjectionBase Projection Premietanie Projection Type Typ premietania Cylinder Valec Sphere Guľa Plane Rovina ... ... ContextRotation Set Rotation operation complete Nastaviť otočenie ContextRotationBase Rotation Otočenie Z Y X CubeToolWidget Cube Kocka Segment Články CylinderToolWidget Segments Články Sides Strany Width Šírka Scale Mierka DeleteCommand Deleting joints may destroy skeletal animations Do you wish to continue? Zmazanie kĺbov môže zničiť kostrovú animáciu Chcete pokračovať? Primitives deleted Útvary zmazané EditKeyframeWin Set keyframe %1 Nastaviť kľúčový rámec EllipsoidToolWidget Smoothness: Hladkosť: Faces: Plochy: Sphere Guľa From Center Checkbox that indicates if ellipsoid is created from center or far corner Od stredu ErrorObject Success Hotovo Canceled Zrušené File is an unknown type Súbor je neznámeho typu Operation not supported for this file type Operácia nie je podporovaná pre tento typ súborov Invalid argument (internal error) Chybný argument (vnútorná chyba) File does not exist Súbor neexistuje Permission denied Prístup zamietnutý Could not open file Nemôžem otvoriť súbor Could not read from file Nemôžem čítať zo súboru File is the wrong type or corrupted Súbor má nesprávny typ alebo je poškodený Unsupported version Nepodporovaná verzia File contains invalid data Súbor obsahuje chybné údaje Unexpected end of file Neočakávaný koniec súboru Unknown error Voľačo sa posralo Could not write file Nemôžem zapisovať do súboru This operation is not supported Táto operácie nie je podporovaná Write not supported, try "Export..." Zápis nie je podporovaný, skúste "Export..." Unrecognized file extension (unknown type) Nerozpoznaná prípona súboru (neznámy typ) ExtrudeWin F1 Help Shortcut Extrude complete Vysunutie dokončené Extrude operation complete Vysunutie ExtrudeWinBase Extrude Vysunutie Extrude options Nastavenie vysunutia X: X: 0 Z: Z: Y: Y: Make Back Faces Vytvoriť zadné plochy E&xtrude Vys&unutie Press F1 for help Stlač F1 pre help Close Zatvoriť GroupCleanBase Group Clean-up Window Okno vyčistenia skupín Merge identical materials Zlúčiť identické materiály Remove unused materials Odstrániť nepoužité materiály Merge identical groups Zlúčiť identické skupiny Remove unused groups Odstrániť nepoužité skupiny Ok Ok Cancel Zrušiť GroupCleanWin F1 Help Shortcut Group Clean-up operation complete Vyčistiť skupiny GroupWinBase Groups Skupiny No group Žiadna skupina New Nový Rename Premenovať Delete Vymazať Select Faces In Group Zvoliť plochy v skupine Unselect Faces In Group Odznačiť plochy v skupine Smoothness: 100 Hladkosť: 100 Max Angle: 000 Max. uhol: 000 Faces Plochy Assign As Group Priradiť ako skupinu Add To Group Pridať do skupiny Texture Textúra No texture Žiadna textúra Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť GroupWindow F1 Help Shortcut New group window title Nová skupina Enter new group name: Zadajte nové meno skupiny: Group name must be between 1 and %1 characters Meno skupiny musí byť medzi 1 a %1 znakmi Bad group name window title Zlé meno skupiny Cannot change cannot change group name, window title Nemožno zmeniť You cannot change the default group name Nemožno zmeniť predvolné meno skupiny Smoothness: Hladkosť: Max Angle: Max. uhol: Group changes operation complete Zmeny skupiny HelpWinBase Help Pomoc Contents Obsah Back Späť Forward Dopredu Ok JointWin F1 Help Shortcut Rename joint window title Premenovať kĺb Enter new joint name: Zadaj meno nového kĺbu: Joint changes operation complete Zmeny kĺbov JointWinBase Joints Kĺby Rename Premenovať Delete Vymazať Selection Výber Select Joint Vertices Zvoliť vrcholy kĺbu Select Unassigned Vertices Zvoliť nepriradené vrcholy Assign Selected to Joint Priradiť označené ku kĺbu Add Selected to Joint Pridať zvolené ku kĺbu F1 for help F1 pre pomoc Ok Cancel Zrušiť KeyConfig V Select Vertices Tool Shortcut F Select Faces Tool Shortcut C Select Connected Mesh Tool Shortcut G Select Groups Tool Shortcut B Select Bone Joints Tool Shortcut T Select Points Tool Shortcut M Move Tool Shortcut R Rotate Tool Shortcut H Hide Unselected Command Shortcut Shift+H Hide Selected Command Shortcut ? Unhide All Command Shortcut ? Delete Delete Command Shortcut Ctrl+D Duplicate Command Shortcut Ctrl+C Copy to Clipboard Command Shortcut Ctrl+V Paste from Clipboard Command Shortcut Insert Extrude Command Shortcut Ctrl+W Weld Command Shortcut Ctrl+N File | New Window Shortcut Ctrl+O File | Open Shortcut Ctrl+S File | Save Shortcut Ctrl+Q File | Quit Shortcut Home View | Frame All Shortcut Shift+Home View | Frame Selected Shortcut Ctrl+G Groups | Edit Groups Shortcut Ctrl+M Groups | Edit Materials Shortcut Ctrl+E Groups | Edit Texture Coordinates Shortcut Ctrl+B Joints | Assign Selected Shortcut Shift+U Unhide All Command Shortcut KeyValueWindowBase Edit Meta Data Editovať meta dáta Name Meno Value Hodnota Ok Cancel Zrušiť LicenseWin GNU General Public License LowLevel Success Hotovo Canceled Zrušené File is an unknown type Súbor je neznámeho typu Operation not supported for this file type Operácia nie je podporovaná pre tento typ súboru Invalid argument (internal error, probably null pointer argument) Chybný argument (cnútorná chyba, pravdeporobne null pointer argument) File does not exist Súbor neexistuje Permission denied Prístup odmietnutý Could not open file Nemôžem otvoriť súbor Could not read from file Nemôžem čítať zo súboru File is the wrong type or corrupted Súbor je nesprávneho typu alebo je poškodený Unsupported version Nepodporovaná verzia File contains invalid data Súbor obsahuje chybné dáta Unexpected end of file Neočakávaný koniec súboru Unknown error Neznáma chyba Invalid error code Nesprávny chybový kód Cannot delete root joint Nemožno zmazať hlavný kĺb Cannot add or delete because you have frame animations. Try "Merge..." instead. Nemožno pridať alebo zmazať lebo máte rámcovú animáciu. Skúste namiesto toho "Zlúčiť...". Could not write file Nemožno zapísať súbor This operation is not supported Táto operácia nie je podporovaná MM3D encountered an unexpected data size problem See Help->About to contact the developers MM3D narazil na problém dát neočakávanej veľkosti Pozrite Pomoc->O programe na kontakt s vývojármi Model has a texture that is not powers of 2 Model má textúru ktorá nie je mocninou 2 Could not load Nemožno načítať Model contains no skeletal animations Model neobsahuje kostrové animácie Model skeletons do not match Kostry modelu sa nezhodujú This looks like a player model. Do you want to load all sections? Toto vyzerá ako model hráča. Chcete načítať všetky sekcie? Could not load texture Nemožno načítať textúry Write not supported, try "Export..." Zápis nie je podporovaný, skúste "Export..." Unrecognized file extension (unknown type) Nerozpoznaná prípona súboru (neznámy typ) MD2 requires all groups to have the same material. MD2 vyžaduje aby všetky skupiny mali rovnaký materiál. MD2 export requires all faces to be grouped. MD2 export vyžaduje aby všetky plochy boli v jednej skupine. MD3 export requires all faces to be grouped. MD3 export vyžaduje aby všetky plochy boli v nejakej skupine. MD3_PATH+filename is to long. MD3_PATH+meno súboru je príliž dlhé. Too many animation frames for MD3 export. Príliš veľa animácií pre MD3 export. Too many points for MD3 export. Príliš veľa bodov pre MD3 export. Too many groups for MD3 export. Príliš veľa skupín pre MD3 export. Too many faces in a single group for MD3 export Príliš veľa plôch v jednej skupine pre MD3 export Too many vertices in a single group for MD3 export Príliš veľa vrcholov v jednej skupine pre MD3 export Point name is too large for MD3 export. Meno bodu je príliš dlhé pre MD3 export. Group name is too large for MD3 export. Meno skupiny je príliš dlhé pre MD3 export. Texture filename is too long. Meno textúry je príliš dlhé. MM3D does not support CAL3D files in XML format MM3D nepodporuje CAL3D v XML formáte The file does not contain any mesh or animation data Súbor neobsahuje žiadnu mriežku ani aimáciu MapDirectionBase Which direction? Ktorý smer? Set new texture coordinates from which direction? Z ktorej strany nastaviť nové súradnice textúry? Front Predok Back Zozadu Left Vľavo Right Vpravo Top Zhora Bottom Spodok Ok Cancel Zrušiť MergeWinBase Merge Model Zlúčiť model Merge location Zlúčiť polohu 0.0 Rotation Otočenie Translation Posunutie Merge Options Zlúčiť nastavenia Include textures Zahrnúť textúry Include animations Zahrnúť animáciu Animation Options Možnosti animácie Append animations Pridaná animácia Merge if possible Zlúčiť ak je to možné Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť MergeWindow F1 Help Shortcut Merge models operation complete Zlúčiť modely MetaWindow F1 Help Shortcut Name meta value key name Názov Value meta value 'value' Hodnota Change meta data operation complete Zmenit metadáta MetaWindowBase Name Meno Value Hodnota Model Meta Data Metadáta modelu New Nový Delete Vymazať Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť ModelViewBase ModelView Perspective Perspektíva Front Predok Back Zozadu Left Zľava Right Zprava Top Zhora Bottom Spodok Orthographic Pravoúhle ModelViewport Could not load background %1 Nemožno načítať pozadie %1 Use the middle mouse button to drag/pan the viewport Použite stredné tlačidlo myši na posunutie/naklonenie výrezu OpenGL error = Invalid Value Chyba OpenGL = Chybná hodnota OpenGL error = Invalid Enum Chyba OpenGL = Cybný výčtový typ OpenGL error = Invalid Operation Chyba OpenGL = Chybná operácia OpenGL error = Stack Overflow Chyba OpenGL = Pretečenie zásobníka OpenGL error = Stack Underflow Chyba OpenGL = Podtečenie zásobníka OpenGL error = Out Of Memory Chyba OpenGL = Nedostatok pamäte OpenGL error = Unknown Chyba OpenGL = Neznáma Ms3dPrompt F1 Help Shortcut Ms3dPromptBase MS3D Filter Options Nastavenie MS3D filtra Format Subversion Podverzia filtra Subversion 0 Podverzia 0 Subversion 1 Podverzia 1 Subversion 2 Podverzia 2 Subversion Options Nastavenie podverzie Vertex Extra Vrchol zvlášť FFFFFFFF Ok Cancel Zrušiť NewAnimBase New Animation Nová animácia &Name &Meno Animation Type Typ animácie &Skeletal &Kostrová Alt+S Alt+K &Frame &Rámcová Alt+F Alt+R &Ok &Ok Alt+O &Cancel &Zrušiť Alt+C Alt+Z ObjPrompt F1 Help Shortcut ObjPromptBase OBJ Filter Options Nastavenie filtra OBJ &Save normals &Uložiť normály Alt+S &Normal Decimal Places Desatinné miesta &normál &Texture Decimal Places Desatinné miesta &textúr &Vertex Decimal Places Desatinné miesta &vrcholov Ok Cancel Zrušiť PaintTextureWin F1 Help Shortcut File name for saved texture? Meno súboru pre uložené textúry? File exists. Overwrite? Súbor existuje. Prepísať? Could not write file: Nemôžem zapísať súbor: PaintTextureWinBase Paint Texture Nakresliť textúru Polygons: Mnohoúholníky: Edges Okraje Filled Vyplnené Filled and Edges Vyplnené a okraje Vertices Vrcholy Hidden Schované Visible Viditeľlné Clear Background Vymazať pozadie Save Size: Uložiť veľkost: 64 128 256 512 1024 2048 x Save Texture... Uložiť textúru... Press F1 for help Stlač F1 pre pomoc Close Zatvoriť PluginWinBase Plugin Plugin Version Verzia Description Popis Status Stav Plugins Pluginy Press F1 for help Stlač F1 pre pomoc Ok PluginWindow F1 Help Shortcut PointWin F1 Help Shortcut Rename point window title Premenovať bod Enter new point name: Zadaj nové meno bodu: Point changes operation complete Zmeny bodu PointWinBase Points Body Rename Premenovať Delete Vymazať Bone Joint Kĺb kosti (none) (nič) F1 for help F1 pre pomoc Ok Cancel Zrušiť PolyToolWidget Fan Vejár Poly Type Typ poly Strip Triangle strip option Pruh Fan Triangle fan option Vejár ProjToolWidget Type Typ Cylinder Cylinder projection type Valec Sphere Sphere projection type Guľa Plane Plane projection type Rovina ProjectionWin F1 Help Shortcut Set Projection Type operation complete Nastaviť typ premietania Set Triangle Projection operation complete Nastaviť trojúholníkové premietanie Apply Projection operation complete Aplikovať premietanie Reset UV Coordinates operation complete Východzie UV premietanie Rename projection window title Premenovať premietanie Enter new point name: Zadajte nové meno bodu: Rename Projection operation complete Premenovať premietanie CTRL+Z Undo shortcut CTRL+Y Redo shortcut ProjectionWinBase Texture Projection Projekcia textúry Material Materiál Test Pattern Testovací vzor Cylinder Valec Sphere Guľa Plane Rovina Show: Ukázať: Type: Typ: Rename Premenovať Zoom: Zväčšenie: 1.0 Remove Faces Odstrániť plochy Add Faces to Projection Pridať plochy do premietania Apply Projection Aplikovať premietanie Reset UV Range Vynulovať UV rozsah Press F1 for help Stlač F1 pre pomoc Close Zatvoriť RgbaWin F1 Help Shortcut RgbaWinBase RGBA Window RGBA Okno Light Property Parametre svetla 0.00 Red Červená Green Zelená Blue Modrá Alpha Priehľadnosť Close Zatvoriť RotateToolWidget X Y Z ScaleToolWidget Proportion Pomer Free Free scaling option Voľné Keep Aspect 2D 2D scaling aspect option Uchovať 2D pomer Keep Aspect 3D 3D scaling aspect option Uchovať 3D pomer Point Bod Center Scale from center Stred Far Corner Scale from far corner Vzdialený roh SelectFaceToolWidget Include Back-facing Plochy kresliť obojstranne SpherifyWin Spherify operation complete Zaguľatiť StatusBar V: Vertices status bar label V: F: Faces status bar label P: G: Groups status bar label S: B: Bone Joints status bar label K: P: Points status bar label B: M: Materials status bar label M: StatusBarBase Form1 Status text Stavový text V:0 V:0 F:0 P:0 G:0 S:0 B:0 K:0 P:0 B:0 T:0 TextWinBase Text Window Textové okno Ok TextureCoord Reset coordinates? window title Vynulovať koordináty? Are you sure you want to reset texture coordinates for this group? Ste si istý že chcete vymazať súradnice textúry pre rúro skupinu? Move texture coordinates Presunúť súradnice textúry F1 Help Shortcut CTRL+Z Undo shortcut CTRL+Y Redo shortcut Select texture coordinates Zvoľte súradnice textúry TextureCoordBase Texture Coordinates Poloha textúry Zoom: Zväčšenie: 1.0 Mouse Tool Nástroj myši Select Zvoliť Move Presunúť Scale Zmenšiť Scale Options Nastavenie mierky Scale from center Mierka od stredu Keep aspect ratio Zachovať pomer Map Scheme Schéma mapy Triangle Trojuholník Quad Obdĺžnik Group Skupina Reset Coordinates Vynulovať koordináty Press F1 for help Stlač F1 pre pomoc Close Zatvoriť Rotate Otočiť Lines Čiary Black Čierna Blue Modrá Green Zelená Cyan Tyrkisová Red Červená Magenta Fialová Yellow Žltá White Biela Selection Výber Rotate CCW Otočiť proti Rotate CW Otočiť V Flip V preklopiť H Flip H preklopiť TextureWindow All Supported Formats ( all texture formats Všetky podporované formáty ( Open texture image Otvoriť obrázok textúry All Files (*) Všetky súbory (*) Could not open file Nemôžem otvoriť súbor Color Material window title Farba materiálu Enter new material name: Zadajte meno nového materiálu: Rename texture window title Premenovať textúru Enter new texture name: Zadajte meno novej textúry: Texture changes Zmeny textúry Shininess Lesk Red Červená Change texture... Change material's texture file Zmeniť textúru... Set texture... Add texture file to material Nastaviť textúru... F1 Help Shortcut TextureWindowBase Materials Materiály None Nič New Material... Nový materiál... Rename Premenovať Delete Vymazať Wrap X Zalomiť X Clamp X Prichytiť X Wrap Y Zalomiť Y Clamp Y Prichytiť Y Change Texture... Zmeniť textúru... X Remove texture Odstrániť textúru Flat Preview Plochý náhľad 3D Preview 3D náhľad 0.00 Alpha Priehľadnosť Green Zelená Blue Modrá Red Červená Ambient Pozadie Diffuse Rozptýlená Specular Zrkadlová Emissive Žiarivá Shininess Lesk Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť Tool Attract Far Pritiahnuť zďaleka Attracting far selected primitives Pritiahnuť zdaleka zvolené útvary Attract far complete Pritiahnuť zďaleka ukončené Attract Near Priťiahnuť zblízka Attracting near selected primitives Pritiahnuť z blízka zvolené útvary Attract near complete Pritiahnuť zblízka hotové Move Background Image Presunúť obrázok pozadia Moving background image Presúvam obrázok pozadia Cannot move background from 3D view Namožno presúvať pozadie v 3D pohľade Background move complete Presun pozadia ukončený Move background image Presunúť obrázok pozadia Scale Background Image Zmenšiť obrázok pozadia Scaling background image Zmena mierky obrázka Cannot scale background from 3D view Nemožno meniť mierku pozadia v 3D pohlade Background scale complete Zmena veľkosti pozadia ukončená Scale background image Zmenšiť obrázok pozadia Cube created Kocka vytvorená Create Cube Vytvoriť kocku Cylinder created Valec vytvorený Create Cylinder Vytvoriť valec Ellipsoid created Elipsoid vytvorený Create Ellipsoid Vytvoriť elipsoid Joint created Kĺb vytvorený Root joint created Koreňový kĺb vytvorený Create Bone Joint Vytvoriť kĺb kosti Moving selected primitives Presúvam zvolené útvary Move complete Presun ukončený Tip: Hold shift to restrict movement to one dimension Tip: Podržte shift na obmedzenie pohybu do jedného smeru Move Presun Point created Bod vytvorený Create Point Vyutvoriť bod Create Polygon Vytvoriť mnohoúholník Projection created Premietanie vytvorené Create Projection Vytvoriť projekciu Rectangle created Obdĺžník vytvorený Create Rectangle Vytvoriť obdĺžník Tip: Hold shift to rotate in 15 degree increments Tip: Podržte shift na otočenie v 15 stupňových krokoch Rotating selected primitives Otáčam zvolené útvary Setting rotation point Nastavujem bod rotácie Rotate complete Otočenie dokončené Rotate Otočiť Scale Zmenšiť Scaling selected primitives Zmena veľkosti zvolených útvarov Scale complete Zmenšenie ukončené Tip: Hold shift to restrict scaling to one dimension Tip: Podržte shift na obmedzenie zmeny veľkosti do jedného smeru Starting selection Začínam výber Selection complete Oznacenie dokončené Select Bone Joints Označiť kĺby kostí Select Connected Mesh Označiť spojené mriežky Select Faces Vybrať plochy Select Groups Vybrať skupinu Select Points Vybrať body Select Projections Označiť premietanie Select Vertices Označiť vrcholy Shear Strihať Starting shear on selected primitives Začínam strihať vybrané útvary Shear complete Strihanie ukončené Torus created Prstenec vytvorený Create Torus Vytvoriť prstenec Vertex created Vrchol vytvorený Create Vertex Vytvoriť vrchol Dragging selected vertex Preťahujem zvolené vrcholy Must a vertex selected Musíte zvoliť vrchol Drag complete Pretiahnutie dokončené Drag Vertex on Edge Presunúť vrchol na okraj Extrude complete Vysunutie ukončené Extrude Vysunutie Must have faces selected to extrude Na vysunutie musíte zvoliť plochy Extruding selected faces Plochy na vysunutie zvolené Select Zvoliť Attract Priťiahnuť Background Image Obrázok pozadia Create Other Vytvoriť ostatné TorusToolWidget Segments Články Sides Strany Width Šírka Circle Kruh From Center Checkbox that indicates if torus is created from center or from far corner Zo stredu TransformWindow Matrix Translate Matica posunutia Matrix Rotate Maticu rotovať Matrix Rotate On Axis Maticu rotovať na osi Matrix Scale Matica zmeny mierky Apply Matrix Aplikovať maticu Transform Cannot Be Undone window title Transformáciu nie je možné vziať späť This transformation cannot be undone. Túto transformáciu nebude možné vziať späť. Are you sure you wish to continue? Naozaj chcete pokračovať? Apply Transformation button Aplikovať transformáciu Cancel Transformation button Zrušiť transformáciu F1 Help Shortcut TransformWindowBase Transform Model Transformovať model 0 X Y Z Translate Posunúť Euler Angles Eulerove uhly Rotate Otočiť Quaternion Angle Uhol Axis Osi 1.0 Scale Zmena mierky 1 (bottom row is translation) (spodný riadok je posunutie) Apply Matrix Aplikovať maticu Matrix Matica Apply to: Aplikovať na: Entire Model and Animations Celý model a animácie Press F1 for help Stlač F1 pre pomoc Close Zatvoriť Selected (including animations) Zvolené (vrátanie animácií) Entire Model (including animations) Celý model (vrátane animácií) ValueWin F1 Help Shortcut ValueWinBase Value Window Okno hodnoty Value Hodnota Press F1 for help Stlač F1 pre pomoc Ok Cancel Zrušiť ViewWindow Some models are unsaved. Save before exiting? Niektoré modely nie sú uložené. Uložiť ich pred uložením? Press F1 for help using any window Stlač F1 pre pomoč ku ktorémukoľvek oknu Animations Animácie Properties Vlastnosti New File|New Nový Open File|Open Otvoriť... Save File|Save Uložiť Save As File|Save As Uložiť ako... Set Background Image... File|Set Background Image Nastaviť obrázok pozadia... Run Script... File|Run Script Spustiť skript... Recent Scripts File|Recent Script Nedávne skripty Merge... File|Merge Zlúčiť... Merge Animations... File|Merge Animations Zlúčiť animáciu... Recent Models File|Recent Models Nedávne modely Plugins... File|Plugins Pluginy... Close File|Close Zatvoriť Quit File|Quit Skončiť Hide Joints View|Hide Joints Schovať kĺby Draw Joint Lines View|Draw Joint Lines Kresliť čiary kĺbov Draw Joint Bones View|Draw Joint Bones Kresliť kĺby kostí Draw Texture Projections View|Draw Texture Projections Kresliť premietanie textúr Hide Texture Projections View|Hide Texture Projections Schovať premietanie textúr Use Red Error Texture View|Use Red Error Texture Použiť červenú chybnú textúru Use Blank Error Texture View|Use Blank Error Texture Použiť prázdnu chybnú textúru Render 3D Lines View|Render 3D Lines Kreslit 3D čiary Hide 3D Lines View|Hide 3D Lines Schovať 3D čiary Draw Back-facing Triangles View|Draw Back-facing Triangles Kresliť zadné plochy trojuholníkov Hide Back-facing Triangles View|Hide Back-facing Triangles Schovať zadné strany trojúholníkov Frame All View|Frame Všetky rámce Frame Selected View|Frame Zvolené rámce Show Properties View|Show Properties Ukázať parametre Render Options View|Render Options Parametre kreslenia 3D Wireframe View|3D 3D drôtený 3D Flat View|3D 3D plochý 3D Smooth View|3D 3D hladký 3D Texture View|3D 3D textúrovaný 3D Alpha Blend View|3D 3D priehľadný Canvas Wireframe View|Canvas 2D drôtený Canvas Flat View|Canvas 2D plochý Canvas Smooth View|Canvas 2D hladký Canvas Texture View|Canvas 2D textúra Canvas Alpha Blend View|Canvas 2D priehľadný 1 View View|Viewports 1 pohľad 1x2 View View|Viewports 1x2 pohľady 2x1 View View|Viewports 2x1 pohľady 2x2 View View|Viewports 2x2 pohľady 2x3 View View|Viewports 2x3 pohľady 3x2 View View|Viewports 3x2 pohľady 3x3 View View|Viewports 3x3 pohľady Viewport Settings... View|Viewport Settings Nastavenie výrezu... Grid Tools|Snap to Grid Mriežka Vertex Tools|Snap to Vertex Vrchol Undo Vrátiť spať Ctrl+Z Undo shortcut Redo Vrátiť zrušené Ctrl+Y Redo shortcut Snap To Prichytiť k Tools Nástroje Edit Groups... Groups|Edit Groups Editovať skupiny... Edit Materials... Groups|Edit Materials Editovať materiály... Reload Textures Groups|Reload Textures Znovu načítať textúry Edit Projection... Groups|Edit Projection Editovať premietanie... Edit Texture Coordinates... Groups|Edit Texture Coordinates Editovať súradnice textúry... Paint Texture... Groups|Paint Texture Namaľovať textúru... Boolean Operation... Groups|Boolean Operation Booleovské operácie... Edit Model Meta Data... Groups|Edit Model Meta Data Upraviť metadáta modelu Transform Model... Groups|Transform Model Transformovať model... Edit Joints... Joints|Edit Joints Upraviť kĺby... Assign Selected to Joint Joints|Assign Selected to Joint Priradiť zvolené ku kĺbom Remove All Influences from Selected Joints|Remove All Influences from Selected Odstrániť všetky body pôsobenia z označených Remove Selected Joint from Influencing Joints|Remove Selected Joint from Influencing Odstrániť zvolené kĺby z bodov pôsobenia Convert Multiple Influences to Single Joints|Convert Multiple Influences to Single Konvertovať body pôsobenia do jedného Select Joint Influences Joints|Select Joint Influences Zvoliť kĺby pôsobenia Select Influenced Vertices Joints|Select Influenced Vertices Zvoliť vrcholy pôsobenia Select Influenced Points Joints|Select Influenced Points Zvoliť body pôsobenia Select Unassigned Vertices Joints|Select Unassigned Vertices Zvoliť nezvolené vrcholy Select Unassigned Points Joints|Select Unassigned Points Zvoliť nepriradené body Start Animation Mode... Animation|Start Animation Mode Spustiť režim animácie... Stop Animation Mode Animation|Stop Animation Mode Zastaviť režim animácie Animation Sets... Animation|Animation Sets Skupiny animácií... Export Animation... Animation|Export Animation Exportovať animáciu... Copy Animation Frame Animation|Copy Animation Frame Kopírovať rámec animácie Paste Animation Frame Animation|Paste Animation Frame Vložiť rámec animácie Clear Animation Frame Animation|Clear Animation Frame Vymazať rámec animácie Set Rotation Keyframe Animation|Set Rotation Keyframe Nastaviť kľúčový rámec otočenia Set Translation Keyframe Animation|Set Translation Keyframe Nastaviť kľúčový rámec posunutia Contents... Help|Contents Obsah... License... Help|License Licencia... About... Help|About O programe... &File menu bar &Súbor &View menu bar &Pohľad &Tools menu bar &Nástroje &Geometry menu bar Ú&tvary &Materials menu bar S&kupiny &Influences menu bar Pôso&benie &Animation menu bar &Animácia &Help menu bar Po&moc All Supported Formats ( Všetky podporované formáty ( ;; All Files (*) ;; Všetky súbory (*) All Files (*) Všetky súbory (*) Save model file as Uložiť model ako File exists. Overwrite? Súbor existuje. Prepísať? All Supported Formats ( model formats Všetky podporované formáty ( Open model file Otvoriť súbor modelu Merge models Zlúčiť modely : : Script %1 complete Skript %1 ukončený Script %1 error %2 Skript %1 chyba %2 Save first? Uložiť prvý? Model has been modified Do you want to save before closing? Model bol zmenený Chcete ho uložiť pred zatvorením? Unknown response: %1, Canceling close request Neznáma odpoveď: %1, Prerušujem zatvorenie Hide Properties View|Hide Properties Schovať vlastnosti Cannot hide with selected projections. Unselect projections now? Nemožno schovať so zvolenými projekciami. Odznačiť najprv projekcie? Hide projections Schovať premietanie Cannot hide with selected joints. Unselect joints now? Nemožno schovať so zvolenými kĺbmi, odznačiť najprv kĺby? Hide bone joints Schovať kĺby kostí You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'edit texture coordinates' window Najprv musíte zvoliť plochu. Použite náztroj 'Označiť plochu'. You must select faces first. Use the 'Select Faces' tool. Notice that user must have faces selected to open 'paint texture' window Najprv musíte zvoliť plochu. Použite náztroj 'Označiť plochu'. Undo %1 Späť %1 Nothing to undo Niet čo vrátiť späť Redo %1 Znova %1 Nothing to redo Nič sa nedá vrátiť späť This model does not have any animations Tento model neobsahuje žiadne animácie Set rotation keframe Nastaviť kĺúčový rámec otočenia Set translation keframe Nastaviť kĺučový rámec posunutia Unknown response: Canceling operation Neznáma odozva: Ruším operáciu [unnamed] For filename in title bar (if not set) [bezmena] assigning %1 vertices and %2 points to joints priraďujem %1 vrcholov a %2 bodov ku kĺbu Assign Selected to Joint Priradiť zvolené ku kĺbom You must have at least one bone joint selected. Musíte mať zvolený aspoň jeden kĺb. Remove All Influences from Selected Odstrániť všetky body pôsobenia z označených Remove Joint from Influencing Odstrániť kĺby z bodov pôsobenia Convert To Single Influence Konvertovať na jeden bod pôsobenia Select Unassigned Vertices Zvoliť nepriradené vrcholy Select Unassigned Points Zvoliť nepriradené body Select Joint Influences Zvoliť kĺby pôsobenia Select Influences Vertices Zvoliť vrcholy pôsobenia Select Influenced Points Zvoliť body pôsobenia Auto-Assign Selected... Joints|Auto-Assign Selected Automaticky priradiť zvolené... Auto-Assign Selected to Bone Joints Automaticky priradiť zvolené ku kĺbom You must have at least one vertex or point selected. Musíte mať zvolený najmenej jeden vrchol alebo bod. Open... File|Open Otvoriť... Save As... File|Save As Uložiť ako... Export... File|Export Export... Edit Model Meta Data... Model|Edit Model Meta Data Upraviť metadáta modelu... Transform Model... Model|Transform Model Transformovať model... Boolean Operation... Model|Boolean Operation Booleovské operácie... Set Background Image... Model|Set Background Image Nastaviť obrázok pozadia... Merge... Model|Merge Zlúčiť... Import Animations... Model|Import Animations Import animácií... Save Animation Images... Animation|Save Animation Images Uložiť obrázky animácií... Copy Selected Keyframes Animation|Copy Animation Frame Kopírovať zvolené kľúčové rámce Paste Selected Keyframes Animation|Paste Animation Frame Vložiť zvolené kľúčové rámce &Model menu bar &Model Mate&rials menu bar Mate&riály All Exportable Formats Všetky exportovateľné formáty All Writable Formats Všetky zapisovateľné formáty Export model Exportovať model All Supported Formats model formats Všetky podporované formáty All Supported Formats Všetky podporované formáty F1 Help Shortcut Export Selected... File|Export Selected Exportovať zvolené... You must have at least 1 face, joint, or point selected to Export Selected Musíte zvoliť aspoň 1 plochu alebo bod na Exportovanie zvoleného You are in animation mode, but there are no animations Ste v režime animácie, ale nie sú tu žiadne animácie Clean Up Groups... Groups|Clean Up Groups Vyčistiť skupiny... ViewportSettings F1 Help Shortcut ViewportSettingsBase Viewport Settings Nastavenie výrezu Canvas Grid Mriežka plátna Default Grid Unit Predvolená jednotka mriežky 3D Grid 3D mriežka Grid Lines Čiary mriežky X/Y Plane Rovina X/Y X/Z Plane Rovina X/Z Y/Z Plane Rovina Y/Z Press F1 for help Stlač F1 pre pomoc &Ok &Ok Alt+O &Cancel &Zrušiť Alt+C Alt+Z Decimal Grid Desiatková mriežka Binary Grid Fixed Grid mm3d-master/i18n/qt_ar.ts000066400000000000000000003762131324021725400154600ustar00rootroot00000000000000 Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True صحيح False خاطئ Insert إدراج Update تحديث Delete حذف Q3FileDialog Copy or Move a File نسخ أو تحريك ملفّ Read: %1 قراءة: %1 Write: %1 كتابة: %1 Cancel إلغاء All Files (*) جميع الملفّات (*) Name الإسم Size السّعة Type الطّراز Date التّاريخ Attributes الخاصّيات &OK &موافقة Look &in: بحث &في: File &name: إ&سم الملفّ: File &type: &طراز الملفّ: Back رجوع One directory up دليل للأعلى Create New Folder صنع دليل جديد List View معاينة بالقائمة Detail View معاينة مفصّلة Preview File Info عرض مقدّم لمعلومات الملفّ Preview File Contents عرض مقدّم لمحتويات الملفّ Read-write قراءة-كتابة Read-only قراءة فقط Write-only كتابة فقط Inaccessible مستحيل التّوصّل إليه Symlink to File وصل رمزي لملفّ Symlink to Directory وصل رمزي لدليل Symlink to Special وصل رمزي لملفّ خاصّ File ملفّ Dir دليل Special ملفّ خاصّ Open فتح Save As حفظ تحت &Open &فتح &Save &حفظ &Rename ت&غيير الإسم &Delete ح&ذف R&eload إ&عادة التّحميل Sort by &Name فرز بال&إسم Sort by &Size فرز بالسّ&عة Sort by &Date فرز بالتّا&ريخ &Unsorted غير &مفروز Sort فرز Show &hidden files ع&رض الملفّات المخفية the file الملفّ the directory الدّليل the symlink الوصل الرّمزي Delete %1 حذف %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>هل تريد فعلا حذف %1 "%2"؟</qt> &Yes &نعم &No &لا New Folder 1 دليل جديد 1 New Folder دليل جديد New Folder %1 دليل جديد %1 Find Directory إيجاد الدّليل Directories دلائل Directory: دليل: Error خطأ %1 File not found. Check path and filename. %1 لم يتمّ إيجاد الملفّ. تحقّق من المسار و إسم الملفّ. All Files (*.*) جميع الملفّات (*.*) Open فتح Select a Directory انتقاء دليل Q3Ftp Not connected غير متصّل Host %1 not found لم يتمّ إيجاد المضيف %1 Connection refused to host %1 رفض الوصل بالمضيف %1 Connected to host %1 تمّ وصل المضيف %1 Connection refused for data connection رفض وصل المعطيات Unknown error خطأ مجهول Connecting to host failed: %1 فشل وصل المضيف: %1 Login failed: %1 فشل التّسجيل: %1 Listing directory failed: %1 فشلت عمليّة وضع قائمة للدّليل: %1 Changing directory failed: %1 فشلت عمليّة تغيير الدّليل: %1 Downloading file failed: %1 فشلت عمليّة تحميل الملفّ: %1 Uploading file failed: %1 فشلت عمليّة تحميل (بعث) الملفّ: %1 Removing file failed: %1 فشلت عمليّة نزع الملفّ: %1 Creating directory failed: %1 فشلت عمليّة صنع الدّليل: %1 Removing directory failed: %1 فشلت عمليّة نزع الدّليل: %1 Connection closed وصل مغلق Host %1 found تمّ إيجاد المضيف %1 Connection to %1 closed تمّ إغلاق الوصل بالمضيف %1 Host found تمّ إيجاد المضيف Connected to host تمّ وصل المضيف Q3Http Unknown error خطأ مجهول Request aborted تمّ إبطال الطّلب No server set to connect to ليس هناك أيّ خادم للوصل Wrong content length طول المحتوى خاطئ Server closed connection unexpectedly الخادم أغلق الوصل بصفة غير متوقّعة Connection refused رفض الوصل Host %1 not found لم يتمّ إيجاد المضيف %1 HTTP request failed فشل طلب الHTTP Invalid HTTP response header صديرة استجابة الHTTP غير صالحة Invalid HTTP chunked body مقطع HTTP غير صالح Host %1 found تمّ إيجاد المضيف %1 Connected to host %1 تمّ وصل المضيف %1 Connection to %1 closed تمّ إغلاق الوصل بالمضيف %1 Host found تمّ إيجاد المضيف Connected to host تمّ وصل المضيف Connection closed وصل مغلق Q3LocalFs Could not read directory %1 لم أستطع قراءة الدّليل %1 Could not create directory %1 لم أستطع صنع الدّليل %1 Could not remove file or directory %1 لم أستطع نزع الملفّ أو الدّليل %1 Could not rename %1 to %2 لم أستطع إعادة تسمية %1 إلى %2 Could not open %1 لم أستطع فتح %1 Could not write %1 لم أستطع كتابة %1 Q3MainWindow Line up تصفيف Customize... تخصيص... Q3NetworkProtocol Operation stopped by the user أوقفت العمليّة من طرف المستعمل Q3ProgressDialog Cancel إلغاء Q3TabDialog OK موافقة Apply تطبيق Help مساعدة Defaults افتراضيات Cancel إلغاء Q3TextEdit &Undo &تراجع &Redo إ&عادة Cu&t &قصّ &Copy &نسخ &Paste ت&لصيق Clear محو Select All انتقاء الجميع Q3ToolBar More... أكثر... Q3UrlOperator The protocol `%1' is not supported المراسم '%1' غير مدعومة The protocol `%1' does not support listing directories المراسم '%1' لا تدعم وضع قوائم الدّلائل The protocol `%1' does not support creating new directories المراسم '%1' لا تدعم صنع دلائل جديدة The protocol `%1' does not support removing files or directories المراسم '%1' لا تدعم نزع الملفّات أو الدّلائل The protocol `%1' does not support renaming files or directories المراسم '%1' لا تدعم إعادة تسمية الملفّات أو الدّلائل The protocol `%1' does not support getting files المراسم '%1' لا تدعم استخلاص الملفّات The protocol `%1' does not support putting files المراسم '%1' لا تدعم وضع الملفّات The protocol `%1' does not support copying or moving files or directories المراسم '%1' لا تدعم نسخ أو تحريك الملفّات أو الدّلائل (unknown) (مجهول) Q3Wizard &Cancel &إلغاء < &Back < &رجوع &Next > ال&تّالي > &Finish إ&نهاء &Help &مساعدة QAbstractSocket Host not found Connection refused رفض الوصل Socket operation timed out QAbstractSpinBox &Step up Step &down QAccel Space فراغ Esc إفلات Tab جدولة Backtab جدولة للوراء Backspace فراغ للوراء Return عودة Enter إدخال Ins إدراج Del حذف Pause وقف Print طباعة SysReq نظام Home منزل End نهاية Left يسار Up فوق Right يمين Down تحت PgUp صفحة للفوق PgDown صفحة للتحت CapsLock إقفال الحروف الكبيرة NumLock إقفال الأعداد ScrollLock إقفال التّحريك Ctrl تحكّم Alt تناوب Shift إزاحة + + F%1 F%1 Menu قائمة الخيارات Help مساعدة Back رجوع Forward للأمام Stop توقّف Refresh إنعاش Volume Down تنقيص الصّوت Volume Mute إغلاق الصّوت Volume Up زيادة الصّوت Bass Boost إنعاش الأصوات الجهورية Bass Up زيادة الأصوات الجهورية Bass Down تنقيص الأصوات الجهورية Treble Up زيادة الأصوات الحادّة Treble Down تنقيص الأصوات الحادّة Media Play لعب الوسط Media Stop توقيف الوسط Media Previous الوسط الأسبق Media Next الوسط التّالي Media Record تسجيل الوسط Favorites المفضّلات Search بحث Standby إنتظار Open URL فتح الوصلة Launch Mail بدأ البريد Launch Media بدأ الوسط Launch (0) بدأ (0) Launch (1) بدأ (1) Launch (2) بدأ (2) Launch (3) بدأ (3) Launch (4) بدأ (4) Launch (5) بدأ (5) Launch (6) بدأ (6) Launch (7) بدأ (7) Launch (8) بدأ (8) Launch (9) بدأ (9) Launch (A) بدأ (A) Launch (B) بدأ (B) Launch (C) بدأ (C) Launch (D) بدأ (D) Launch (E) بدأ (E) Launch (F) بدأ (F) Meta ما فوق QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. RTL Executable '%1' requires Qt %2, found Qt %3. البرنامج '%1' يتطلّب Qt %2، تمّ إيجاد Qt %3. Incompatible Qt Library Error خطأ: مكتبة Qt غير موافقة Activate Activates the program's main window QAquaStyle OK موافقة Cancel إلغاء QAxServerBase &Help &مساعدة QColorDialog Hu&e: ال&صّبغة: &Sat: التّ&شبّع: &Val: ال&قيمة: &Red: أ&حمر: &Green: أ&خضر: Bl&ue: أ&زرق: A&lpha channel: قناة أ&لفا: &Basic colors الألوان القا&عديّة &Custom colors الأل&وان المخصّصة &Define Custom Colors >> تع&ريف الألوان المخصّصة >> OK موافقة Cancel إلغاء &Add to Custom Colors الإ&ضافة إلى الألوان المخصّصة Select color إنتقاء اللّون QDataTable True صحيح False خاطئ Insert إدراج Update تحديث Delete حذف QDateTimeEdit AM am PM pm QDialog What's This? ما هذا؟ Help مساعدة QDialogButtons Yes to All OK to All No to All Cancel All Yes نعم OK موافقة No لا Cancel إلغاء Apply تطبيق Ignore Retry Abort Help مساعدة %1 to All QDirModel Name الإسم Size السّعة Type الطّراز Modified QErrorMessage &Show this message again أ&عرض مجدّداهذاالبلاغ &OK &موافقة Debug Message: بلاغ تصحيح الأخطاء: Warning: إنذار: Fatal Error: خطأ قاتل: QFileDialog Copy or Move a File نسخ أو تحريك ملفّ Read: %1 قراءة: %1 Write: %1 كتابة: %1 Cancel إلغاء All Files (*) جميع الملفّات (*) Name الإسم Size السّعة Type الطّراز Date التّاريخ Attributes الخاصّيات OK موافقة Look &in: بحث &في: File &name: إ&سم الملفّ: File &type: &طراز الملفّ: Back رجوع One directory up دليل للأعلى Create New Folder صنع دليل جديد List View معاينة بالقائمة Detail View معاينة مفصّلة Preview File Info عرض مقدّم لمعلومات الملفّ Preview File Contents عرض مقدّم لمحتويات الملفّ Read-write قراءة-كتابة Read-only قراءة فقط Write-only كتابة فقط Inaccessible مستحيل التّوصّل إليه Symlink to File وصل رمزي لملفّ Symlink to Directory وصل رمزي لدليل Symlink to Special وصل رمزي لملفّ خاصّ File ملفّ Dir دليل Special ملفّ خاصّ Open فتح Save As حفظ تحت &Open &فتح &Save &حفظ &Rename ت&غيير الإسم &Delete ح&ذف R&eload إ&عادة التّحميل Sort by &Name فرز بال&إسم Sort by &Size فرز بالسّ&عة Sort by &Date فرز بالتّا&ريخ &Unsorted غير &مفروز Sort فرز Show &hidden files ع&رض الملفّات المخفية the file الملفّ the directory الدّليل the symlink الوصل الرّمزي Delete %1 حذف %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>هل تريد فعلا حذف %1 "%2"؟</qt> &Yes &نعم &No &لا New Folder 1 دليل جديد 1 New Folder دليل جديد New Folder %1 دليل جديد %1 Find Directory إيجاد الدّليل Directories دلائل Save حفظ Error خطأ %1 File not found. Check path and filename. %1 لم يتمّ إيجاد الملفّ. تحقّق من المسار و إسم الملفّ. All Files (*.*) جميع الملفّات (*.*) Open فتح Select a Directory انتقاء دليل Directory: دليل: %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer &Reload Parent Directory Look in: File name: Files of type: QFileDialogPrivate Sort فرز &Open &فتح &Rename ت&غيير الإسم &Delete ح&ذف Sort by &Name فرز بال&إسم Sort by &Size فرز بالسّ&عة Sort by &Date فرز بالتّا&ريخ &Unsorted غير &مفروز Show &hidden files ع&رض الملفّات المخفية Back رجوع Create New Folder صنع دليل جديد List View معاينة بالقائمة Detail View معاينة مفصّلة Open فتح Cancel إلغاء %1 Directory not found. Please verify the correct directory name was given. QFont Latin لاتيني Greek يوناني Cyrillic سريالي Armenian أرميني Georgian جيورجي Runic روني Ogham أوغمي Hebrew عبري Arabic عربي Syriac سرياني Thaana ثعاني Devanagari ديفاناغاري Bengali بنغالي Gurmukhi غرموخي Gujarati غوجاراتي Oriya أوريي Tamil تاميلي Telugu تيلوغي Kannada كنّادي Malayalam مالايالامي Sinhala سنهالي Thai تايي Lao لاوسي Tibetan تبتي Myanmar ميانماري Khmer خميري Han هاني Hiragana هيراغاني Katakana كاتاكاني Hangul هنغولي Bopomofo بوبوموفو Yi يي Ethiopic إثيوبي Cherokee شيروكي Canadian Aboriginal كندي أصلي Mongolian منغولي Currency Symbols رموز العملة Letterlike Symbols رموز شبه حرفية Number Forms أشكال عددية Mathematical Operators مؤثّرات رياضية Technical Symbols رموز تقنية Geometric Symbols رموز هندسية Miscellaneous Symbols رموز متنوّعة Enclosed and Square مطوّقة و مربّعة Braille براي Unicode يونيكود QFontDialog &Font ال&خطّ Font st&yle &طراز الخطّ &Size ال&حجم Effects تأثيرات Stri&keout ت&شطيب &Underline ت&سطير &Color &لون Sample عيّنة Scr&ipt &رموز الخطّ OK موافقة Apply تطبيق Cancel إلغاء Close إغلاق Select Font انتقاء الخطّ Wr&iting System QFtp Host %1 found تمّ إيجاد المضيف %1 Host found تمّ إيجاد المضيف Connected to host %1 تمّ وصل المضيف %1 Connected to host تمّ وصل المضيف Connection to %1 closed تمّ إغلاق الوصل بالمضيف %1 Connection closed وصل مغلق Host %1 not found لم يتمّ إيجاد المضيف %1 Connection refused to host %1 رفض الوصل بالمضيف %1 Unknown error خطأ مجهول Connecting to host failed: %1 فشل وصل المضيف: %1 Login failed: %1 فشل التّسجيل: %1 Listing directory failed: %1 فشلت عمليّة وضع قائمة للدّليل: %1 Changing directory failed: %1 فشلت عمليّة تغيير الدّليل: %1 Downloading file failed: %1 فشلت عمليّة تحميل الملفّ: %1 Uploading file failed: %1 فشلت عمليّة تحميل (بعث) الملفّ: %1 Removing file failed: %1 فشلت عمليّة نزع الملفّ: %1 Creating directory failed: %1 فشلت عمليّة صنع الدّليل: %1 Removing directory failed: %1 فشلت عمليّة نزع الدّليل: %1 Not connected غير متصّل Connection refused for data connection رفض وصل المعطيات QHeader %1 %1 QHostInfo Unknown error خطأ مجهول QHostInfoAgent Host not found Unknown address type Unknown error خطأ مجهول QHttp Connection refused رفض الوصل Host %1 not found لم يتمّ إيجاد المضيف %1 Wrong content length طول المحتوى خاطئ HTTP request failed فشل طلب الHTTP Host %1 found تمّ إيجاد المضيف %1 Host found تمّ إيجاد المضيف Connected to host %1 تمّ وصل المضيف %1 Connected to host تمّ وصل المضيف Connection to %1 closed تمّ إغلاق الوصل بالمضيف %1 Connection closed وصل مغلق Unknown error خطأ مجهول Request aborted تمّ إبطال الطّلب No server set to connect to ليس هناك أيّ خادم للوصل Server closed connection unexpectedly الخادم أغلق الوصل بصفة غير متوقّعة Invalid HTTP response header صديرة استجابة الHTTP غير صالحة Invalid HTTP chunked body مقطع HTTP غير صالح QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error خطأ مجهول QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK موافقة Cancel إلغاء QLineEdit &Undo &تراجع &Redo إ&عادة Cu&t &قصّ &Copy &نسخ &Paste ت&لصيق Clear محو Select All انتقاء الجميع Delete حذف QLineEditPrivate &Undo &تراجع &Redo إ&عادة Cu&t &قصّ &Copy &نسخ &Paste ت&لصيق Delete حذف Select All انتقاء الجميع QLocalFs Could not rename %1 to %2 لم أستطع إعادة تسمية %1 إلى %2 Could not open %1 لم أستطع فتح %1 Could not write %1 لم أستطع كتابة %1 Could not read directory %1 لم أستطع قراءة الدّليل %1 Could not create directory %1 لم أستطع صنع الدّليل %1 Could not remove file or directory %1 لم أستطع نزع الملفّ أو الدّليل %1 QMainWindow Line up تصفيف Customize... تخصيص... QMenuBar About حول Config تشكيل Preference تفضيل Options خيارات Setting ضبط Setup إعداد Quit إنتهاء Exit خروج QMessageBox OK موافقة Cancel إلغاء &Yes &نعم &No &لا &Abort إ&بطال &Retry إ&عادة &Ignore ت&جاهل <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for multiplatform GUI &amp; application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>حول Qt</h3><p>هذا البرنامج يستعمل Qt إصدار %1.</p><p>Qt هو عبارة عن طقم أدوات C++ لتطوير البرامج البيانية على جميع المنصّات.</p><p>Qt تمكّن من حمل نفس المصدر إلى مايكروسوفت&nbsp;ويندوز، نظام &nbsp;التّشغيل ماكX، لينكس، وجميع أنظمة يونيكس التّجارية الرّائدة.<br>Qt متوفّر كذلك للآلات المحمولة.</p><p>Qt منتوج لشركة ترولتك. أنظر <tt>http://www.trolltech.com/qt/</tt> للمزيد من المعلومات.</p> Yes to &All N&o to All About Qt Help مساعدة <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused رفض الوصل The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QNetworkProtocol Operation stopped by the user أوقفت العمليّة من طرف المستعمل QObject All Files (*) جميع الملفّات (*) All Files (*.*) جميع الملفّات (*.*) Open فتح Save As حفظ تحت Open فتح Select a Directory انتقاء دليل Drive File ملفّ Directory Symbolic Link Unknown False خاطئ True صحيح QPageSetupDialog OK موافقة Cancel إلغاء Portrait صورة Landscape منظر QPrintDialog locally connected موصل محليّا Aliases: %1 بدائل: %1 unknown مجهول Unknown Location موقع مجهول OK موافقة Cancel إلغاء Printer settings إعدادات الطّابعة Print in color if available طباعة بالألوان إن توفّرت Print in grayscale طباعة بالتّدريج الرّمادي Print destination وجهة الطّباعة Print to printer: طباعة في الطاّبعة: Printer الطّابعة Host المضيف Comment تعليق Print to file: طباعة في الملفّ: Browse... تصفّح... Options خيارات Print all طباعة الجميع Print range مدى الطّباعة From page: من الصّفحة: To page: إلى الصّفحة: Print first page first طباعة الصّفحة الأولى أوّلا Print last page first طباعة الصّفحة الخيرة أوّلا Number of copies: عدد النّسخ: Paper format مقاييس الورق Portrait صورة Landscape منظر A0 (841 x 1189 mm) أ0 (841 × 1189 مم) A1 (594 x 841 mm) أ1 (594 × 841 مم) A2 (420 x 594 mm) أ2 (420 × 594 مم) A3 (297 x 420 mm) أ3 (297 × 420 مم) A4 (210x297 mm, 8.26x11.7 inches) أ4 (210×297 مم، 8.26×11.70 بوصة) A5 (148 x 210 mm) أ5 (148 × 210 مم) A6 (105 x 148 mm) أ6 (105 × 148 مم) A7 (74 x 105 mm) أ7 (74 × 105 مم) A8 (52 x 74 mm) أ8 (52 × 74 مم) A9 (37 x 52 mm) أ9 (37 × 52 مم) B0 (1000 x 1414 mm) ب0 (1000 × 1414 مم) B1 (707 x 1000 mm) ب1 (707 × 1000 مم) B2 (500 x 707 mm) ب2 (500 × 707 مم) B3 (353 x 500 mm) ب3 (353 × 500 مم) B4 (250 x 353 mm) ب4 (250 × 353 مم) B5 (176 x 250 mm, 6.93x9.84 inches) ب5 (176 × 250 مم، 6.93×9.84 بوصة) B6 (125 x 176 mm) ب6 (125 × 176 مم) B7 (88 x 125 mm) ب7 (88 × 125 مم) B8 (62 x 88 mm) ب4 (62 × 88 مم) B9 (44 x 62 mm) ب9 (44 × 62 مم) B10 (31 x 44 mm) ب10 (31 × 44 مم) C5E (163 x 229 mm) سي5إي (163 × 229 مم) DLE (110 x 220 mm) دي أل إي (110 × 220 مم) Executive (7.5x10 inches, 191x254 mm) إداري (7.50×10 بوصة، 191×254 مم) Folio (210 x 330 mm) ملفّ (210 × 330 مم) Ledger (432 x 279 mm) دفتر (432 × 279 مم) Legal (8.5x14 inches, 216x356 mm) قانوني (8.50×14 بوصة، 216×356 مم) Letter (8.5x11 inches, 216x279 mm) رسالة (8.50×11 بوصة، 216×279 مم) Tabloid (279 x 432 mm) جريدة (279 × 432 مم) US Common #10 Envelope (105 x 241 mm) غلاف رسالة أمريكية متداولة رقم 10 (105 × 241 مم) Setup Printer إعداد الطاّبعة PostScript Files (*.ps);;All Files (*) ملفّات بوستسكريبت (ps.*);;جميع الملفّات (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) B5 (176 x 250 mm, 6.93 x 9.84 inches) Executive (7.5 x 10 inches, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Print selection Page size: Orientation: Paper source: QPrintDialogPrivate Printer settings إعدادات الطّابعة Print in color if available طباعة بالألوان إن توفّرت Print in grayscale طباعة بالتّدريج الرّمادي Print destination وجهة الطّباعة Print to printer: طباعة في الطاّبعة: Print to file: طباعة في الملفّ: Browse... تصفّح... Options خيارات Print all طباعة الجميع Print range مدى الطّباعة From page: من الصّفحة: To page: إلى الصّفحة: Print first page first طباعة الصّفحة الأولى أوّلا Print last page first طباعة الصّفحة الخيرة أوّلا Number of copies: عدد النّسخ: Paper format مقاييس الورق Portrait صورة Landscape منظر PostScript Files (*.ps);;All Files (*) ملفّات بوستسكريبت (ps.*);;جميع الملفّات (*) OK موافقة Cancel إلغاء QProcess Unknown error خطأ مجهول QProgressBar %1% QProgressDialog Cancel إلغاء QRegExp no error occurred لم يحدث هناك أيّ خطأ disabled feature used تمّ استعمال خاصيّة التّوقيف bad char class syntax خطأ نركيبي: صنف الرّمز bad lookahead syntax خطأ تركيبي: النّظر إلى الأمام bad repetition syntax خطأ نركيبي: تكرار invalid octal value قيمة ثمانية غبر صالحة missing left delim الفاصل الأيسر ناقص unexpected end نهاية غير متوقّعة met internal limit تمّ الوصول إلى الحدّ الدّاخلي QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space فراغ Esc إفلات Tab جدولة Backtab جدولة للوراء Backspace فراغ للوراء Return عودة Enter إدخال Ins إدراج Del حذف Pause وقف Print طباعة SysReq نظام Home منزل End نهاية Left يسار Up فوق Right يمين Down تحت PgUp صفحة للفوق PgDown صفحة للتحت CapsLock إقفال الحروف الكبيرة NumLock إقفال الأعداد ScrollLock إقفال التّحريك Menu قائمة الخيارات Help مساعدة Back رجوع Forward للأمام Stop توقّف Refresh إنعاش Volume Down تنقيص الصّوت Volume Mute إغلاق الصّوت Volume Up زيادة الصّوت Bass Boost إنعاش الأصوات الجهورية Bass Up زيادة الأصوات الجهورية Bass Down تنقيص الأصوات الجهورية Treble Up زيادة الأصوات الحادّة Treble Down تنقيص الأصوات الحادّة Media Play لعب الوسط Media Stop توقيف الوسط Media Previous الوسط الأسبق Media Next الوسط التّالي Media Record تسجيل الوسط Favorites المفضّلات Search بحث Standby إنتظار Open URL فتح الوصلة Launch Mail بدأ البريد Launch Media بدأ الوسط Launch (0) بدأ (0) Launch (1) بدأ (1) Launch (2) بدأ (2) Launch (3) بدأ (3) Launch (4) بدأ (4) Launch (5) بدأ (5) Launch (6) بدأ (6) Launch (7) بدأ (7) Launch (8) بدأ (8) Launch (9) بدأ (9) Launch (A) بدأ (A) Launch (B) بدأ (B) Launch (C) بدأ (C) Launch (D) بدأ (D) Launch (E) بدأ (E) Launch (F) بدأ (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert إدراج Delete حذف Escape System Request Select Yes نعم No لا Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl تحكّم Shift إزاحة Alt تناوب Meta ما فوق + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete حذف Delete this record? حذف هذاالتّسجيل؟ Yes نعم No لا Insert إدراج Update تحديث Save edits? حفظ التّغييرات؟ Cancel إلغاء Confirm تأكيد Cancel your edits? إلغاء التّغييرات؟ QTabDialog OK موافقة Apply تطبيق Help مساعدة Defaults افتراضيات Cancel إلغاء QTcpServer Socket operation unsupported QTextEdit &Undo &تراجع &Redo إ&عادة Cu&t &قصّ &Copy &نسخ &Paste ت&لصيق Clear محو Select All انتقاء الجميع Delete حذف QTitleBar System Menu قائمة خيارات النّظام Shade تظليل Unshade إلغاء التّظليل Normalize تطبيع Minimize تصغير Maximize تكبير Close إغلاق QToolBar More... أكثر... QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QUrlOperator The protocol `%1' is not supported المراسم '%1' غير مدعومة The protocol `%1' does not support listing directories المراسم '%1' لا تدعم وضع قوائم الدّلائل The protocol `%1' does not support creating new directories المراسم '%1' لا تدعم صنع دلائل جديدة The protocol `%1' does not support removing files or directories المراسم '%1' لا تدعم نزع الملفّات أو الدّلائل The protocol `%1' does not support renaming files or directories المراسم '%1' لا تدعم إعادة تسمية الملفّات أو الدّلائل The protocol `%1' does not support getting files المراسم '%1' لا تدعم استخلاص الملفّات The protocol `%1' does not support putting files المراسم '%1' لا تدعم وضع الملفّات The protocol `%1' does not support copying or moving files or directories المراسم '%1' لا تدعم نسخ أو تحريك الملفّات أو الدّلائل (unknown) (مجهول) QWSDecoration &Restore ا&ستعاد &Move &تحريك &Size &حجم Mi&nimize ت&صغير Ma&ximize ت&كبير Close إغلاق Windows وندوز KDE كيدي KDE2 كيدي2 BeOS نظام التّشغيل بي Hydro هيدرو Default افتراضي QWhatsThisAction What's This? ما هذا؟ QWhatsThisButton What's this? ما هذا؟ QWidget * QWizard &Cancel &إلغاء < &Back < &رجوع &Next > ال&تّالي > &Finish إ&نهاء &Help &مساعدة QWorkspace &Restore ا&ستعاد &Move &تحريك &Size &حجم Mi&nimize ت&صغير Ma&ximize ت&كبير &Close إ&غلاق Stay on &Top ال&بقاء في الأمام Sh&ade ت&ظليل %1 - [%2] %1 - [%2] Minimize تصغير Restore Down استعاد في الأسفل Close إغلاق &Unshade إ&لغاء التّظليل QWorkspacePrivate &Restore ا&ستعاد &Move &تحريك Mi&nimize ت&صغير Ma&ximize ت&كبير &Close إ&غلاق Stay on &Top ال&بقاء في الأمام Sh&ade ت&ظليل %1 - [%2] %1 - [%2] Minimize تصغير Restore Down استعاد في الأسفل Close إغلاق &Unshade إ&لغاء التّظليل QXml no error occurred لم يحدث هناك أيّ خطأ error triggered by consumer أطلق الخطأ من طرف المستهلك unexpected end of file نهاية غير متوقّعة للملفّ more than one document type definition أكثر من تعريف لطراز الوثيقة error occurred while parsing element حدث خطأ عند تحليل تركيب العنصر tag mismatch عدم تطابق العلامة error occurred while parsing content حدث خطأ عند تحليل تركيب المحتوى unexpected character رمز غير متوقّع invalid name for processing instruction إسم غير صالح لتعليمة المعالجة version expected while reading the XML declaration الإصدار متوقّع عند قراءة إعلان الXML wrong value for standalone declaration قيمة خاطئة لإعلان مستقلّ encoding declaration or standalone declaration expected while reading the XML declaration إعلان التّرميز أو إعلان مستقلّ متوقّع عند قراءة إعلان الXML standalone declaration expected while reading the XML declaration إعلان مستقلّ متوقّع عند قراءة إعلان الXML error occurred while parsing document type definition حدث خطأ عند تحليل تركيب تعريف طراز الوثيقة letter is expected حرف متوقّع error occurred while parsing comment حدث خطأ عند تحليل تركيب التّعليق error occurred while parsing reference حدث خطأ عند تحليل تركيب المرجع internal general entity reference not allowed in DTD المرجع إلى كيان داخلي عامّ غير مسموح به في الDTD external parsed general entity reference not allowed in attribute value المرجع إلى كيان خارجي عامّ معرب غير مسموح به في قيمة الخاصّية external parsed general entity reference not allowed in DTD المرجع إلى كيان خارجي عامّ معرب غير مسموح به في الDTD unparsed entity reference in wrong context مرجع إلى كيان غير معرب في سياق خاطئ recursive entities كيانات معاودة error in the text declaration of an external entity خطأ في التّعريف النّصّي لكيان خارجي QtMultiLineEdit Undo تراجع Redo إعادة Cut قصّ Copy نسخ Paste تلصيق Paste special... تلصيق خاصّ... Clear محو Select All انتقاء الجميع Transport Auth error mm3d-master/i18n/qt_cs.ts000066400000000000000000003636251324021725400154660ustar00rootroot00000000000000 Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True Ano False Ne Insert Vložit Update Aktualizovat Delete Smazat Q3FileDialog Copy or Move a File Kopírovat nebo přesunout soubor Read: %1 Číst: %1 Write: %1 Zapsat: %1 Cancel Zrušit All Files (*) Všechny soubory (*) Name Jméno Size Velikost Type Typ Date Datum Attributes Vlastnosti &OK &OK Look &in: Náhled: File &name: Jméno souboru: File &type: Typ souboru: Back Zpět One directory up O jeden adresář výš Create New Folder Vytvořit novou složku List View Seznam pohledů Detail View Detailní pohled Preview File Info Náhled informací o souboru Preview File Contents Náhled obsahu souboru Read-write Prozápis i pro čtení Read-only Pouze ke čtení Write-only Pouze pro zápis Inaccessible Nepřístupné Symlink to File Odkaz na soubor Symlink to Directory Odkaz na adresář Symlink to Special Odkaz na zvláštní soubor File Soubor Dir Dir Special Speciální Open Otevřít Save As Uložit jako &Open &Otevřít &Save &Uložit &Rename P&řejmenovat &Delete &Smazat R&eload O&bnovit Sort by &Name Setřídit podle &jména Sort by &Size Setřídit podle &velikosti Sort by &Date Setřídit podle &datumu &Unsorted &Nesetříděné Sort Třídit Show &hidden files Ukázat &skryté soubory the file soubor the directory adresář the symlink odkaz Delete %1 Smazat %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Skutečně chcete smazat %1 "%2"?</qt> &Yes &Ano &No &Ne New Folder 1 Nová složka 1 New Folder Nová složka New Folder %1 Nová složka %1 Find Directory Najít adresář Directories Adresáře Directory: Adresář: Error Chyba %1 File not found. Check path and filename. %1 Soubor nebyl nalezen. překontrolujte cestu a jméno souboru. All Files (*.*) Všechny soubory (*.*) Open Otevřít Select a Directory Vyberte adresář Q3Ftp Not connected Nepřipojen Connection refused to host %1 Odmítnuto připojení k počítači %1 Connection refused for data connection Spojení pro datový přenos odmítnuto Unknown error Neznámá chyba Connecting to host failed: %1 Selhalo připojení k počítači: %1 Login failed: %1 Přihlášení selhalo: %1 Listing directory failed: %1 Selhalo vypsání adresáře: %1 Changing directory failed: %1 Selhala změna adresáře: %1 Downloading file failed: %1 Selhalo stažení souboru: %1 Uploading file failed: %1 Selhalo nahrání souboru: %1 Removing file failed: %1 Selhalo odstranění souboru: %1 Creating directory failed: %1 Selhalo vytváření adresáře: %1 Removing directory failed: %1 Selhalo odstranění adresáře: %1 Connection to %1 closed Připojení k %1 ukončeno Host found Počítač nalezen Connected to host Připojen k počítači Q3Http Unknown error Neznámá chyba Request aborted Dotaz zrušen No server set to connect to Nenastaven žádný server k připojení Wrong content length Chybná délka obsahu Server closed connection unexpectedly Server neočekávaně ukončil připojení Connection refused Spojení odmítnuto HTTP request failed HTTP požadavek selhal Invalid HTTP response header Chybná hlavička HTTP odpovědi Invalid HTTP chunked body Chybné HTTP tělo Connection to %1 closed Připojení k %1 ukončeno Host found Počítač nalezen Connected to host Připojen k počítači Q3LocalFs Could not read directory %1 Nelze číst z adresáře(new line) %1 Could not create directory %1 Nelze vytvořit adresář(new line) %1 Could not remove file or directory %1 Nelze odstranit soubor nebo adresář(new line) %1 Could not rename %1 to %2 Nelze přejmenovat(new line) %1(new line) na(new line) %2 Could not open %1 Nelze otevřít(new line) %1 Could not write %1 Nelze zapsat(new line) %1 Q3MainWindow Line up Zarovnat Customize... Upravit... Q3NetworkProtocol Operation stopped by the user Operace zastavena uživatelem Q3ProgressDialog Cancel Zrušit Q3TabDialog OK OK Apply Použít Help Nápověda Defaults Výchozí Cancel Zrušit Q3TextEdit &Undo &Zpět &Redo Zn&ovu Cu&t Vyjmou&t &Copy &Kopírovat &Paste V&ložit Clear Vyprázdnit Select All Vybrat vše Q3ToolBar More... Více... Q3UrlOperator The protocol `%1' is not supported Protocol `%1' není podporován The protocol `%1' does not support listing directories Protocol `%1' nepodporuje vypsání adresářů The protocol `%1' does not support creating new directories Protocol `%1' nepodporuje vytváření nových adresářů The protocol `%1' does not support removing files or directories Protocol `%1' nepodporuje odstranění souborů nebo adresářů The protocol `%1' does not support renaming files or directories Protocol `%1' nepodporuje přejmenování souborů nebo adresářů The protocol `%1' does not support getting files Protocol `%1' nepodporuje získávání souborů The protocol `%1' does not support putting files Protocol `%1' nepodporuje zasílání souborů The protocol `%1' does not support copying or moving files or directories Protocol `%1' nepodporuje kopírování nebo přesouvání souborů nebo adresářů (unknown) (neznámý) Q3Wizard &Cancel Z&rušit < &Back < &Zpět &Next > &Další > &Finish Do&končit &Help Nápo&věda QAbstractSocket Host not found Connection refused Spojení odmítnuto Socket operation timed out QAbstractSpinBox &Step up Step &down QAccel Space Prostor Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Tisk SysReq SysReq Home Home End End Left Vlevo Up Nahoru Right Vpravo Down Down PgUp PageUp PgDown PageDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Ctrl Ctrl Alt Alt Shift Shift + + F%1 F%1 Menu Nabídka Help Nápověda Back Zpět Forward Vpřed Stop Stop Refresh Obnovit Volume Down Ubrat hlasitost Volume Mute Ztlumit Volume Up Přidat hlasitost Bass Boost Basy Bass Up Přidat basy Bass Down Ubrat basy Treble Up Přidat výšky Treble Down Ubrat výšky Media Play Přehrát Media Stop Zastavit Media Previous Předchozí Media Next Následující Media Record Nahrávání Favorites Oblíbené Search Hledat Standby Standby Open URL Otevřít adresu Launch Mail Pošta Launch Media Média Launch (0) Spustit (0) Launch (1) Spustit (1) Launch (2) Spustit (2) Launch (3) Spustit (3) Launch (4) Spustit (4) Launch (5) Spustit (5) Launch (6) Spustit (6) Launch (7) Spustit (7) Launch (8) Spustit (8) Launch (9) Spustit (9) Launch (A) Spustit (A) Launch (B) Spustit (B) Launch (C) Spustit (C) Launch (D) Spustit (D) Launch (E) Spustit (E) Launch (F) Spustit (F) Meta Meta QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. QT_LAYOUT_DIRECTION Executable '%1' requires Qt %2, found Qt %3. proměnná '%1' vyžaduje Qt %2, nalezena Qt %3. Incompatible Qt Library Error Chyba nekompatibility knihovny Qt Activate Activates the program's main window QAquaStyle OK OK Cancel Zrušit QAxServerBase &Help Nápo&věda QColorDialog Hu&e: Zabar&vení: &Sat: &Sat: &Val: &Hod: &Red: Č&ervená: &Green: &Zelená: Bl&ue: Mo&drá: A&lpha channel: A&lfa kanál: &Basic colors &Základní barvy &Custom colors &Vlastní barvy &Define Custom Colors >> &Zvolit vlastní barvy >> OK OK Cancel Zrušit &Add to Custom Colors Přid&at k vlastním barvám Select color Zvolit barvu QDataTable True Ano False Ne Insert Vložit Update Aktualizovat Delete Smazat QDateTimeEdit AM am PM pm QDialog What's This? Co je toto? Help Nápověda QDialogButtons Yes to All OK to All No to All Cancel All Yes Ano OK OK No Ne Cancel Zrušit Apply Použít Ignore Retry Abort Help Nápověda %1 to All QDirModel Name Jméno Size Velikost Type Typ Modified QErrorMessage &Show this message again &Znovu zobrazit tuto zprávu &OK &OK Debug Message: Ladicí hlášení: Warning: Varování: Fatal Error: Fatální chyba: QFileDialog Copy or Move a File Kopírovat nebo přesunout soubor Read: %1 Číst: %1 Write: %1 Zapsat: %1 Cancel Zrušit All Files (*) Všechny soubory (*) Name Jméno Size Velikost Type Typ Date Datum Attributes Vlastnosti OK OK Look &in: Náhled: File &name: Jméno souboru: File &type: Typ souboru: Back Zpět One directory up O jeden adresář výš Create New Folder Vytvořit novou složku List View Seznam pohledů Detail View Detailní pohled Preview File Info Náhled informací o souboru Preview File Contents Náhled obsahu souboru Read-write Prozápis i pro čtení Read-only Pouze ke čtení Write-only Pouze pro zápis Inaccessible Nepřístupné Symlink to File Odkaz na soubor Symlink to Directory Odkaz na adresář Symlink to Special Odkaz na zvláštní soubor File Soubor Dir Dir Special Speciální Open Otevřít Save As Uložit jako &Open &Otevřít &Save &Uložit &Rename P&řejmenovat &Delete &Smazat R&eload O&bnovit Sort by &Name Setřídit podle &jména Sort by &Size Setřídit podle &velikosti Sort by &Date Setřídit podle &datumu &Unsorted &Nesetříděné Sort Třídit Show &hidden files Ukázat &skryté soubory the file soubor the directory adresář the symlink odkaz Delete %1 Smazat %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Skutečně chcete smazat %1 "%2"?</qt> &Yes &Ano &No &Ne New Folder 1 Nová složka 1 New Folder Nová složka New Folder %1 Nová složka %1 Find Directory Najít adresář Directories Adresáře Save Uložit Error Chyba %1 File not found. Check path and filename. %1 Soubor nebyl nalezen. překontrolujte cestu a jméno souboru. All Files (*.*) Všechny soubory (*.*) Open Otevřít Select a Directory Vyberte adresář Directory: Adresář: %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer &Reload Parent Directory Look in: File name: Files of type: QFileDialogPrivate Sort Třídit &Open &Otevřít &Rename P&řejmenovat &Delete &Smazat Sort by &Name Setřídit podle &jména Sort by &Size Setřídit podle &velikosti Sort by &Date Setřídit podle &datumu &Unsorted &Nesetříděné Show &hidden files Ukázat &skryté soubory Back Zpět Create New Folder Vytvořit novou složku List View Seznam pohledů Detail View Detailní pohled Open Otevřít Cancel Zrušit %1 Directory not found. Please verify the correct directory name was given. QFont Latin Latinské Greek Řecké Cyrillic Azbuka Armenian Arménské Georgian Gruzínské Runic Runové Ogham Ogham Hebrew Hebrejské Arabic Arabské Syriac Syrské Thaana Thaana Devanagari Devanagari Bengali Bengálské Gurmukhi Gurmukhi Gujarati Gujarati Oriya Oriya Tamil Tamilské Telugu Telugu Kannada Kannada Malayalam Malajské Sinhala Sinhala Thai Thajské Lao Laoské Tibetan Tibetská Myanmar Myanmar Khmer Khmérské Han Han Hiragana Hiragana Katakana Katakana Hangul Hangul Bopomofo Bopomofo Yi Yi Ethiopic Etiopská Cherokee Cherokee Canadian Aboriginal Kanadské domorodé Mongolian Mongolská Currency Symbols Symboly měny Letterlike Symbols Písmenné symboly Number Forms Formát čísel Mathematical Operators Matematické operátory Technical Symbols Technické symboly Geometric Symbols Geometrické symboly Miscellaneous Symbols Různé symboly Enclosed and Square Zabalené Braille Braille Unicode Unicode QFontDialog &Font &Písmo Font st&yle St&yl písma &Size Veliko&st Effects Efekty Stri&keout Přeš&krtnuté &Underline &Podtržené &Color &Barva Sample Vzorek Scr&ipt Skr&ipt OK OK Apply Použít Cancel Zrušit Close Zavřít Select Font Vybrat písmo Wr&iting System QFtp Host %1 found Počítač %1 nalezen Host found Počítač nalezen Connected to host %1 Připojen k počítači %1 Connected to host Připojen k počítači Connection to %1 closed Připojení k %1 ukončeno Connection closed Připojení ukončeno Host %1 not found Počítač %1 nenalezen Connection refused to host %1 Odmítnuto připojení k počítači %1 Unknown error Neznámá chyba Connecting to host failed: %1 Selhalo připojení k počítači: %1 Login failed: %1 Přihlášení selhalo: %1 Listing directory failed: %1 Selhalo vypsání adresáře: %1 Changing directory failed: %1 Selhala změna adresáře: %1 Downloading file failed: %1 Selhalo stažení souboru: %1 Uploading file failed: %1 Selhalo nahrání souboru: %1 Removing file failed: %1 Selhalo odstranění souboru: %1 Creating directory failed: %1 Selhalo vytváření adresáře: %1 Removing directory failed: %1 Selhalo odstranění adresáře: %1 Not connected Nepřipojen Connection refused for data connection Spojení pro datový přenos odmítnuto QHeader %1 %1 QHostInfo Unknown error Neznámá chyba QHostInfoAgent Host not found Unknown address type Unknown error Neznámá chyba QHttp Connection refused Spojení odmítnuto Host %1 not found Počítač %1 nebyl nalezen Wrong content length Chybná délka obsahu HTTP request failed HTTP požadavek selhal Host %1 found Počítač %1 nenalezen Host found Počítač nalezen Connected to host %1 Připojení k počítači %1 Connected to host Připojen k počítači Connection to %1 closed Připojení k %1 ukončeno Connection closed Spojení ukončeno Unknown error Neznámá chyba Request aborted Dotaz zrušen No server set to connect to Nenastaven žádný server k připojení Server closed connection unexpectedly Server neočekávaně ukončil připojení Invalid HTTP response header Chybná hlavička HTTP odpovědi Invalid HTTP chunked body Chybné HTTP tělo QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error Neznámá chyba QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK OK Cancel Zrušit QLineEdit &Undo &Zpět &Redo Zn&ovu Cu&t Vyjmou&t &Copy &Kopírovat &Paste V&ložit Clear Vyprázdnit Select All Vybrat vše Delete Smazat QLineEditPrivate &Undo &Zpět &Redo Zn&ovu Cu&t Vyjmou&t &Copy &Kopírovat &Paste V&ložit Delete Smazat Select All Vybrat vše QLocalFs Could not rename %1 to %2 Nelze přejmenovat(new line) %1(new line) na(new line) %2 Could not open %1 Nelze otevřít(new line) %1 Could not write %1 Nelze zapsat(new line) %1 Could not read directory %1 Nelze číst z adresáře(new line) %1 Could not create directory %1 Nelze vytvořit adresář(new line) %1 Could not remove file or directory %1 Nelze odstranit soubor nebo adresář(new line) %1 QMainWindow Line up Zarovnat Customize... Upravit... QMenuBar About Informace o aplikaci Config Nastavení Preference Preference Options Možnosti Setting Nastavení Setup Nastavení Quit Ukončit Exit Ukončit QMessageBox OK OK Cancel Zrušit &Yes &Ano &No &Ne &Abort Přer&ušit &Retry &Obnovit &Ignore &Ignorovat <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for multiplatform GUI &amp; application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>Informace o knihovně Qt</h3> <p>Tento program používá knihovnu Qt verze %1.</p> <p>Qt je multiplatformní C++ knihovna pro návrh grafických aplikací od firmy Trolltech. Qt umožňuje jednoduchou přenositelnost aplikací mezi Windows 95/98/NT/2000, Linuxem, Solarisem, Mac OS X, HP-UX a mnoha dalšími verzemi Unixu s grafickým prostředím X11. <br>Dostupná je také podpora pro mobilní zařízení.</p> <p>Více informací naleznete na <tt>http://www.trolltech.com/qt/</tt>.</p> Yes to &All N&o to All About Qt Help Nápověda <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused Spojení odmítnuto The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QNetworkProtocol Operation stopped by the user Operace zastavena uživatelem QObject All Files (*) Všechny soubory (*) All Files (*.*) Všechny soubory (*.*) Open Otevřít Save As Uložit jako Open Otevřít Select a Directory Vyberte adresář Drive File Soubor Directory Symbolic Link Unknown False Ne True Ano QPageSetupDialog OK OK Cancel Zrušit Portrait Na výšku Landscape Na šířku QPrintDialog locally connected připojen lokálně Aliases: %1 Aliasy: %1 unknown neznámý Unknown Location Neznámé umístění OK OK Cancel Zrušit Printer settings Nastavení tiskárny Print in color if available Tisknout pokud lze barevně Print in grayscale Tisknout černobíle Print destination Určení tisku Print to printer: Tisknout na tiskárnu: Printer Tiskárna Host Počítač Comment Komentář Print to file: Tisk do souboru: Browse... Listovat... Options Možnosti Print all Tisknout vše Print range Tisknout rozsah From page: Od stránky: To page: Do stránky: Print first page first Nejdřív tisknout první stránku Print last page first nejdřív tisknout poslední stránku Number of copies: Počet kopií: Paper format Formát papíru Portrait Na výšku Landscape Na šířku A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A4 (210x297 mm, 8.26x11.7 inches) A4 (210x297 mm, 8.26x11.7 palců) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B4 (250 x 353 mm) B5 (176 x 250 mm, 6.93x9.84 inches) B5 (176 x 250 mm, 6.93x9.84 palců) B6 (125 x 176 mm) B6 (125 x 176 mm) B7 (88 x 125 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Executive (7.5x10 inches, 191x254 mm) Executive (7.5x10 palců, 191x254 mm) Folio (210 x 330 mm) Fólie (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Legal (8.5x14 inches, 216x356 mm) Legal (8.5x14 palců, 216x356 mm) Letter (8.5x11 inches, 216x279 mm) Letter (8.5x11 palců, 216x279 mm) Tabloid (279 x 432 mm) Tabloid (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) US Common #10 obálka (105 x 241 mm) Setup Printer Nastavení tiskárny PostScript Files (*.ps);;All Files (*) PostScript soubory (*.ps);;všechny soubory (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) B5 (176 x 250 mm, 6.93 x 9.84 inches) Executive (7.5 x 10 inches, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Print selection Page size: Orientation: Paper source: QPrintDialogPrivate Printer settings Nastavení tiskárny Print in color if available Tisknout pokud lze barevně Print in grayscale Tisknout černobíle Print destination Určení tisku Print to printer: Tisknout na tiskárnu: Print to file: Tisk do souboru: Browse... Listovat... Options Možnosti Print all Tisknout vše Print range Tisknout rozsah From page: Od stránky: To page: Do stránky: Print first page first Nejdřív tisknout první stránku Print last page first nejdřív tisknout poslední stránku Number of copies: Počet kopií: Paper format Formát papíru Portrait Na výšku Landscape Na šířku PostScript Files (*.ps);;All Files (*) PostScript soubory (*.ps);;všechny soubory (*) OK OK Cancel Zrušit QProcess Unknown error Neznámá chyba QProgressBar %1% QProgressDialog Cancel Zrušit QRegExp no error occurred nedošlo k žádné chybě disabled feature used používána nepovolená funkce bad char class syntax špatná syntaxe znaku třídy bad lookahead syntax špatná syntaxe bad repetition syntax špatná syntaxe opakování invalid octal value chybná osmičková hodnota missing left delim chybějící levé ohraničení unexpected end neočekávaně skončil met internal limit interní limit QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space Prostor Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Tisk SysReq SysReq Home Home End End Left Vlevo Up Nahoru Right Vpravo Down Down PgUp PageUp PgDown PageDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Menu Nabídka Help Nápověda Back Zpět Forward Vpřed Stop Stop Refresh Obnovit Volume Down Ubrat hlasitost Volume Mute Ztlumit Volume Up Přidat hlasitost Bass Boost Basy Bass Up Přidat basy Bass Down Ubrat basy Treble Up Přidat výšky Treble Down Ubrat výšky Media Play Přehrát Media Stop Zastavit Media Previous Předchozí Media Next Následující Media Record Nahrávání Favorites Oblíbené Search Hledat Standby Standby Open URL Otevřít adresu Launch Mail Pošta Launch Media Média Launch (0) Spustit (0) Launch (1) Spustit (1) Launch (2) Spustit (2) Launch (3) Spustit (3) Launch (4) Spustit (4) Launch (5) Spustit (5) Launch (6) Spustit (6) Launch (7) Spustit (7) Launch (8) Spustit (8) Launch (9) Spustit (9) Launch (A) Spustit (A) Launch (B) Spustit (B) Launch (C) Spustit (C) Launch (D) Spustit (D) Launch (E) Spustit (E) Launch (F) Spustit (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert Vložit Delete Smazat Escape System Request Select Yes Ano No Ne Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl Ctrl Shift Shift Alt Alt Meta Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete Smazat Delete this record? Smazat záznam? Yes Ano No Ne Insert Vložit Update Aktualizovat Save edits? Uložit změněné? Cancel Zrušit Confirm Potvrdit Cancel your edits? Zrušit? QTabDialog OK OK Apply Použít Help Nápověda Defaults Výchozí Cancel Zrušit QTcpServer Socket operation unsupported QTextEdit &Undo &Zpět &Redo Zn&ovu Cu&t Vyjmou&t &Copy &Kopírovat &Paste V&ložit Clear Vyprázdnit Select All Vybrat vše Delete Smazat QTitleBar System Menu Systémová nabídka Shade Zarolovat Unshade Vyrolovat Normalize Normalizovat Minimize Minimalizovat Maximize Maximalizovat Close Zavřít QToolBar More... Více... QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QUrlOperator The protocol `%1' is not supported Protocol `%1' není podporován The protocol `%1' does not support listing directories Protocol `%1' nepodporuje vypsání adresářů The protocol `%1' does not support creating new directories Protocol `%1' nepodporuje vytváření nových adresářů The protocol `%1' does not support removing files or directories Protocol `%1' nepodporuje odstranění souborů nebo adresářů The protocol `%1' does not support renaming files or directories Protocol `%1' nepodporuje přejmenování souborů nebo adresářů The protocol `%1' does not support getting files Protocol `%1' nepodporuje získávání souborů The protocol `%1' does not support putting files Protocol `%1' nepodporuje zasílání souborů The protocol `%1' does not support copying or moving files or directories Protocol `%1' nepodporuje kopírování nebo přesouvání souborů nebo adresářů (unknown) (neznámý) QWSDecoration &Restore Obno&vit &Move Přes&unout &Size Veliko&st Mi&nimize Mi&nimalizovat Ma&ximize Ma&ximalizovat Close Zavřít Windows Okna KDE KDE KDE2 KDE2 BeOS BeOS Hydro Hydro Default Výchozí QWhatsThisAction What's This? Co je toto? QWhatsThisButton What's this? Co je toto? QWidget * QWizard &Cancel Z&rušit < &Back < &Zpět &Next > &Další > &Finish Do&končit &Help Nápo&věda QWorkspace &Restore Obno&vit &Move Přes&unout &Size Veliko&st Mi&nimize Mi&nimalizovat Ma&ximize Ma&ximalizovat &Close &Zavřít Stay on &Top Zůs&tat navrchu Sh&ade Z&arolovat %1 - [%2] %1 - [%2] Minimize Minimalizovat Restore Down Obnovit dolů Close Zavřít &Unshade &Vyrolovat QWorkspacePrivate &Restore Obno&vit &Move Přes&unout &Size Veliko&st Mi&nimize Mi&nimalizovat Ma&ximize Ma&ximalizovat &Close &Zavřít Stay on &Top Zůs&tat navrchu Sh&ade Z&arolovat %1 - [%2] %1 - [%2] Minimize Minimalizovat Restore Down Obnovit dolů Close Zavřít &Unshade &Vyrolovat QXml no error occurred nedošlo k chybě error triggered by consumer chyba zapřičiněná uživatelem unexpected end of file neočekávaný konec souboru more than one document type definition více než jedna definice typu dokumentu error occurred while parsing element při parsování prvku došlo k chybě tag mismatch nesprávný tag error occurred while parsing content při parsování obsahu došlo k chybě unexpected character neočekávaný znak invalid name for processing instruction chybné jméno instrukce procesu version expected while reading the XML declaration při čtení XML hlavičky je očekávána verze wrong value for standalone declaration špatná hodnota deklarace standardu encoding declaration or standalone declaration expected while reading the XML declaration při čtení XML hlavičky je očekávána deklarace kódování nebo standardu standalone declaration expected while reading the XML declaration při čtení XML hlavičky je očekávána deklarace standardu error occurred while parsing document type definition při parsování definice typu dokumentu došlo k chybě letter is expected je očekáváno písmeno error occurred while parsing comment při parsování komentáře došlo k chybě error occurred while parsing reference při parsování odkazu došlo k chybě internal general entity reference not allowed in DTD #, fuzzy interní obecná entita není v DTD povolena external parsed general entity reference not allowed in attribute value #, fuzzy reference na externě parsované obecné entity nejsou v hodnotě atributu povoleny external parsed general entity reference not allowed in DTD #, fuzzy reference na externě parsované obecné entity nejsou v DTD povoleny unparsed entity reference in wrong context odkaz na neparsovanou entitu je ve špatném kontextu recursive entities rekurzivní entity error in the text declaration of an external entity chyba v textu deklarace externí entity internal general entity reference not allowed in DTD interní obecná entita není v DTD povolena external parsed general entity reference not allowed in attribute value reference na externě parsované obecné entity nejsou v hodnotě atributu povoleny external parsed general entity reference not allowed in DTD reference na externě parsované obecné entity nejsou v DTD povoleny QtMultiLineEdit Undo Zpět Redo Znovu Cut Vyjmout Copy Kopírovat Paste Vložit Paste special... Vložit jinak... Clear Vyprázdnit Select All Vybrat vše Transport Auth error mm3d-master/i18n/qt_de.ts000066400000000000000000003745611324021725400154520ustar00rootroot00000000000000 @default OK OK Cancel Abbrechen Q3Accel %1, %2 not defined %1, %2 nicht definiert Ambiguous %1 not handled Mehrdeutige %1 nicht gehandhabt Q3DataTable True Wahr False Falsch Insert Einfügen Update Aktualisieren Delete Löschen Q3FileDialog Copy or Move a File Datei kopieren oder verschieben Read: %1 Lesen: %1 Write: %1 Schreiben: %1 Cancel Abbrechen All Files (*) Alle Dateien (*) Name Name Size Größe Type Typ Date Datum Attributes Attribute &OK &OK Look &in: Su&chen in: File &name: Datei&name: File &type: Datei&typ: Back Zurück One directory up Ein Verzeichnis zurück Create New Folder Neuen Ordner erstellen List View Liste Detail View Ausführlich Preview File Info Voransicht der Datei-Info Preview File Contents Voransicht des Datei-Inhalts Read-write Lesen/Schreiben Read-only Nur Lesen Write-only Nur Schreiben Inaccessible Gesperrt Symlink to File Verknüpfung mit Datei Symlink to Directory Verknüpfung mit Verzeichnies Symlink to Special Verknüpfung mit Spezialdatei File Datei Dir Verzeichnis Special Spezialattribut Open Öffnen Save As Speichern unter &Open &Öffnen &Save S&peichern &Rename &Umbenennen &Delete &Löschen R&eload Erne&ut laden Sort by &Name Nach &Name sortieren Sort by &Size Nach &Größe sortieren Sort by &Date Nach &Datum sortieren &Unsorted &Unsortiert Sort Sortieren Show &hidden files &Versteckte Dateien anzeigen the file die Datei the directory das Verzeichnis the symlink die Verknüpfung Delete %1 %1 löschen <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Sind Sie sicher, dass Sie %1 "%2" löschen möchten?</qt> &Yes &Ja &No N&ein New Folder 1 Neues Verzeichnis 1 New Folder Neues Verzeichnis New Folder %1 Neues Verzeichnis %1 Find Directory Verzeichnis suchen Directories Verzeichnisse Directory: Verzeichnis: Error Fehler %1 File not found. Check path and filename. %1 Datei konnte nicht gefunden werden. Überprüfen Sie Pfad und Dateinamen. All Files (*.*) Alle Dateien (*.*) Open Öffnen Select a Directory Wählen Sie ein Verzeichnis Q3Ftp Not connected Keine Verbindung Host %1 not found Rechner %1 nicht gefunden Connection refused to host %1 Verbindung mit %1 verweigert Connected to host %1 Verbunden mit Rechner %1 Connection refused for data connection Verbindung für die Daten Verbindung verweigert Unknown error Unbekannter Fehler Connecting to host failed: %1 Verbindung mit Rechner schlug fehl: %1 Login failed: %1 Anmeldung schlug fehl: %1 Listing directory failed: %1 Inhalt des Verzeichnises kann nicht angezeigt werden: %1 Changing directory failed: %1 Ändern des Verzeichnises schlug fehl: %1 Downloading file failed: %1 Herunterladen der Datei schlug fehl: %1 Uploading file failed: %1 Hochladen der Datei schlug fehl: %1 Removing file failed: %1 Löschen der Datei schlug fehl: %1 Creating directory failed: %1 Erstellen des Verzeichnises schlug fehl: %1 Removing directory failed: %1 Löschen des Verzeichnises schlug fehl: %1 Connection closed Verbindung beendet Host %1 found Rechner %1 gefunden Connection to %1 closed Verbindung mit %1 beendet Host found Rechner gefunden Connected to host Verbindung mit Rechner besteht Q3Http Unknown error Unbekannter Fehler Request aborted Anfrage wurde abgebrochen No server set to connect to Kein Rechner gesetzt für die Verbindung Wrong content length Falsche Content-Length Server closed connection unexpectedly Server hat die Verbindung unerwartet geschlossen Connection refused Verbindung verweigert Host %1 not found Rechner %1 nicht gefunden HTTP request failed HTTP Anfrage schlug fehl Invalid HTTP response header Ungültiger HTTP Antwort-Header Invalid HTTP chunked body Ungültiger HTTP Chunked-Body Host %1 found Rechner %1 gefunden Connected to host %1 Verbunden mit Rechner %1 Connection to %1 closed Verbindung mit %1 beendet Host found Rechner gefunden Connected to host Verbindung mit Rechner besteht Connection closed Verbindung beendet Q3LocalFs Could not read directory %1 Konnte Verzeichnis nicht lesen %1 Could not create directory %1 Konnte Verzeichnis nicht erstellen %1 Could not remove file or directory %1 Konnte Datei oder Verzeichnis nicht löschen %1 Could not rename %1 to %2 Konnte nicht umbenannt werden: %1 nach %2 Could not open %1 Konnte nicht geöffnet werden: %1 Could not write %1 Konnte nicht geschrieben werden: %1 Q3MainWindow Line up Ausrichten Customize... Anpassen... Q3NetworkProtocol Operation stopped by the user Operation von Benutzer angehalten Q3ProgressDialog Cancel Abbrechen Q3TabDialog OK OK Apply Anwenden Help Hilfe Defaults Defaults Cancel Abbrechen Q3TextEdit &Undo &Rückgängig &Redo Wieder&herstellen Cu&t &Ausschneiden &Copy &Kopieren &Paste Einf&ügen Clear Löschen Select All Alles auswählen Q3ToolBar More... Mehr... Q3UrlOperator The protocol `%1' is not supported Das Protokoll `%1' wird nicht unterstützt The protocol `%1' does not support listing directories Das Protokoll `%1' unterstützt nicht das Auflisten von Verzeichnissen The protocol `%1' does not support creating new directories Das Protokoll `%1' unterstützt nicht das Anlegen neuer Verzeichnisse The protocol `%1' does not support removing files or directories Das Protokoll `%1' unterstützt nicht das Löschen von Dateien oder Verzeichnissen The protocol `%1' does not support renaming files or directories Das Protokoll `%1' unterstützt nicht das Umbenennen von Dateien oder Verzeichnissen The protocol `%1' does not support getting files Das Protokoll `%1' unterstützt nicht das Laden von Files The protocol `%1' does not support putting files Das Protokoll `%1' unterstützt nicht das Speichern von Files The protocol `%1' does not support copying or moving files or directories Das Protokoll `%1' unterstützt nicht das Kopieren oder Verschieben von Dateien oder Verzeichnissen (unknown) (unbekannt) Q3Wizard &Cancel &Abbrechen < &Back < &Zurück &Next > &Weiter > &Finish Ab&schließen &Help &Hilfe QAbstractSocket Host not found Rechner konnte nicht gefunden werden Connection refused Verbindung verweigert Socket operation timed out Das Zeitlimit für die Operation wurde überschritten QAbstractSpinBox &Step up &Inkrementieren Step &down &Dekrementieren QAccel Space Leertaste Esc Esc Tab Tab Backtab Rück-Tab Backspace Rücktaste Return Return Enter Enter Ins Einfg Del Entf Pause Pause Print Druck SysReq SysReq Home Pos1 End Ende Left Links Up Hoch Right Rechts Down Runter PgUp Bild aufwärts PgDown Bild abwärts CapsLock Feststelltaste NumLock Zahlen-Feststelltaste ScrollLock Rollen-Feststelltaste Ctrl Strg + + Alt Alt Shift Umschalt F%1 F%1 Menu Menü Help Hilfe Back Zurück Forward Vorwärts Stop Abbrechen Refresh Aktualisieren Volume Down Lautstärke - Volume Mute Ton aus Volume Up Lautstärke + Bass Boost Bass Boost Bass Up Bass + Bass Down Bass - Treble Up Höhen + Treble Down Höhen - Media Play Wiedergabe Media Stop Stopp Media Previous Vorheriger Media Next Nächster Media Record Aufzeichnen Favorites Favoriten Search Suchen Standby Standby Open URL Öffne URL Launch Mail Start Mail Launch Media Start Media Player Launch (0) Start (0) Launch (1) Start (1) Launch (2) Start (2) Launch (3) Start (3) Launch (4) Start (4) Launch (5) Start (5) Launch (6) Start (6) Launch (7) Start (7) Launch (8) Start (8) Launch (9) Start (9) Launch (A) Start (A) Launch (B) Start (B) Launch (C) Start (C) Launch (D) Start (D) Launch (E) Start (E) Launch (F) Start (F) Meta Meta QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. LTR Executable '%1' requires Qt %2, found Qt %3. Applikation '%1' benötigt Qt %2, aber Qt %3 gefunden. Incompatible Qt Library Error Qt Bibliothek ist inkompatibel Activate Aktivieren Activates the program's main window Aktiviert das Programmhauptfenster QAquaStyle OK OK Cancel Abbrechen QAxServerBase &Help &Hilfe QColorDialog Hu&e: Farb&ton: &Sat: &Sat: &Val: &Val: &Red: &Rot: &Green: &Grün: Bl&ue: Bla&u: A&lpha channel: A&lphakanal: &Basic colors Grundfar&ben &Custom colors &Benutzerdefinierte Farben &Define Custom Colors >> Eigene Farben &definieren >> OK OK Cancel Abbrechen &Add to Custom Colors Zu benutzerdefinierten Farben &hinzufügen Select color Farbauswahl QDataManager Delete this record? Diesen Datensatz löschen? Yes Ja No Nein Save edits? Änderungen speichern? Cancel Abbrechen Confirm Bestätigen Cancel your edits? Änderungen verwerfen? QDataTable True Wahr False Falsch Insert Einfügen Update Aktualisieren Delete Löschen QDateTimeEdit AM AM am am PM PM pm pm QDialog What's This? Direkthilfe Help Hilfe QDialogButtons Yes to All Ja zu allem OK to All OK zu allem No to All Nein zu allem Cancel All Alle abbrechen Yes Ja OK OK No Nein Cancel Abbrechen Apply Anwenden Ignore Ignorieren Retry Wiederholen Abort Abbrechen Help Hilfe %1 to All %1 zu allem QDirModel Name Name Size Größe Type Typ Modified Geändert QErrorMessage &Show this message again Diese Meldungen noch einmal an&zeigen &OK &OK Debug Message: Debug Ausgabe: Warning: Warnung: Fatal Error: Fehler: QFileDialog Copy or Move a File Datei kopieren oder verschieben Read: %1 Lesen: %1 Write: %1 Schreiben: %1 Cancel Abbrechen All Files (*) Alle Dateien (*) Name Name Size Größe Type Typ Date Datum Attributes Attribute OK OK Look &in: Su&chen in: File &name: Datei&name: File &type: Datei&typ: Back Zurück One directory up Ein Verzeichnis zurück Create New Folder Neuen Ordner erstellen List View Liste Detail View Details Preview File Info Voransicht der Datei-Info Preview File Contents Voransicht des Datei-Inhalts Read-write Lesen/Schreiben Read-only Nur Lesen Write-only Nur Schreiben Inaccessible Gesperrt Symlink to File Link auf Datei Symlink to Directory Link auf Verzeichnies Symlink to Special Link auf Spezialdatei File Datei Dir Verzeichnis Special Spezialattribut Open Öffnen Save As Speichern unter &Open &Öffnen &Save S&peichern &Rename &Umbenennen &Delete &Löschen R&eload Erne&ut laden Sort by &Name Nach &Name sortieren Sort by &Size Nach &Größe sortieren Sort by &Date Nach &Datum sortieren &Unsorted &Unsortiert Sort Sortieren Show &hidden files &Versteckte Dateien anzeigen the file die Datei the directory das Verzeichnis the symlink den symbolischen Link Delete %1 %1 löschen <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Sind Sie sicher, dass Sie %1 "%2" löschen möchten?</qt> &Yes &Ja &No N&ein New Folder 1 Neues Verzeichnis 1 New Folder Neues Verzeichnis New Folder %1 Neues Verzeichnis %1 Find Directory Verzeichnis suchen Directories Verzeichnisse Save Speichern Error Fehler %1 File not found. Check path and filename. %1 Datei wurde nicht gefunden. Überprüfen Sie Pfad und Dateinamen. All Files (*.*) Alle Dateien (*.*) Open Öffnen Select a Directory Wählen Sie ein Verzeichnis Directory: Verzeichnis: %1 already exists. Do you want to replace it? Die Datei %1 existiert bereits. Soll sie überschreiben werden? %1 File not found. Please verify the correct file name was given. %1 Die Datei konnte nicht gefunden werden. Stellen Sie sicher, dass der Dateiname richtig ist. My Computer Mein Computer &Reload Erne&ut laden Parent Directory Elternverzeichnis Look in: Suchen in: File name: Dateiname: Files of type: Dateien des Typs: QFileDialogPrivate Sort Sortieren &Open &Öffnen &Rename &Umbenennen &Delete &Löschen Sort by &Name Nach &Name sortieren Sort by &Size Nach &Größe sortieren Sort by &Date Nach &Datum sortieren &Unsorted &Unsortiert Show &hidden files &Versteckte Dateien anzeigen Back Zurück Create New Folder Neuen Ordner erstellen List View Liste Detail View Ausführlich Open Öffnen Cancel Abbrechen %1 Directory not found. Please verify the correct directory name was given. %1 Das Verzeichnis konnte nicht gefunden werden. Stellen Sie sicher, dass der Verzeichnisname richtig ist. QFont Latin Latein Greek Griechisch Cyrillic Kyrillisch Armenian Armenisch Georgian Georgisch Runic Runen Ogham Ogham Hebrew Hebräisch Arabic Arabisch Syriac Syrisch Thaana Thaana Devanagari Devanagari Bengali Bengalisch Gurmukhi Gurmukhi Gujarati Gujarati Oriya Oriya Tamil Tamilisch Telugu Telugu Kannada Kannada Malayalam Malayalam Sinhala Sinhala Thai Thailändisch Lao Lao Tibetan Tibetisch Myanmar Myanmar Khmer Khmer Han Han Hiragana Hiragana Katakana Katakana Hangul Hangul Bopomofo Bopomofo Yi Yi Ethiopic Äthiopisch Cherokee Skripte der Cherokee Indianer Canadian Aboriginal Skripte der kanadischen Ureinwohner Mongolian Mongolisch Currency Symbols Währungssymbole Letterlike Symbols Buchstabenartige Symbole Number Forms Ziffernformen Mathematical Operators Mathematische Operatoren Technical Symbols Technische Symbole Geometric Symbols Geometrische Symbole Miscellaneous Symbols Verschiedene Symbole Enclosed and Square Eingeschlossene Symbole Braille Blindenschrift Unicode Unicode Reverse Oblique Umgekehrtes Schräg Reverse Italic Umgekehrtes Kursiv Other Sonstiges Oblique Schräg Italic Kursiv Normal Normal QFontDialog &Font &Schriftart Font st&yle Schrifts&til &Size &Größe Effects Effekte Stri&keout Durch&gestrichen &Underline &Unterstrichen &Color &Farbe Sample Beispiel Scr&ipt Schr&iftsystem OK OK Apply Anwenden Cancel Abbrechen Close Schließen Select Font Schriftart auswählen Wr&iting System &Schriftsystem QFtp Host %1 found Rechner %1 gefunden Host found Rechner gefunden Connected to host %1 Verbunden mit Rechner %1 Connected to host Verbindung mit Rechner besteht Connection to %1 closed Verbindung mit %1 beendet Connection closed Verbindung beendet Login Incorrect Ungültige Anmeldung Host %1 not found Rechner %1 konnte nicht gefunden werden Connection refused to host %1 Verbindung mit %1 verweigert Unknown error Unbekannter Fehler Connecting to host failed: %1 Verbindung mit Rechner schlug fehl: %1 Login failed: %1 Anmeldung schlug fehl: %1 Listing directory failed: %1 Inhalt des Verzeichnises kann nicht angezeigt werden: %1 Changing directory failed: %1 Ändern des Verzeichnises schlug fehl: %1 Downloading file failed: %1 Herunterladen der Datei schlug fehl: %1 Uploading file failed: %1 Hochladen der Datei schlug fehl: %1 Removing file failed: %1 Löschen der Datei schlug fehl: %1 Creating directory failed: %1 Erstellen des Verzeichnises schlug fehl: %1 Removing directory failed: %1 Löschen des Verzeichnises schlug fehl: %1 Not connected Keine Verbindung Connection refused for data connection Verbindung für die Daten Verbindung verweigert QFtpPI Host %1 not found Rechner %1 nicht gefunden Connection refused to host %1 Verbindung mit %1 verweigert Connected to host %1 Verbunden mit Rechner %1 QHeader %1 %1 QHostInfo Unknown error Unbekannter Fehler QHostInfoAgent Host not found Rechner konnte nicht gefunden werden Unknown address type Unbekannter Adresstyp Unknown error Unbekannter Fehler QHttp Connection refused Verbindung verweigert Host %1 not found Rechner %1 konnte nicht gefunden werden Connection closed by %1 %1 hat Verbindung beendet Invalid HTTP reply header Ungültiger HTTP Reply-Header Wrong content length Falsche Content-Length HTTP request failed HTTP Anfrage schlug fehl Host %1 found Rechner %1 gefunden Host found Rechner gefunden Connected to host %1 Verbunden mit Rechner %1 Connected to host Verbindung mit Rechner besteht Connection to %1 closed Verbindung mit %1 beendet Connection closed Verbindung beendet Unknown error Unbekannter Fehler Request aborted Anfrage wurde abgebrochen No server set to connect to Kein Rechner gesetzt für die Verbindung Server closed connection unexpectedly Server hat die Verbindung unerwartet geschlossen Invalid HTTP response header Ungültiger HTTP Antwort-Header Invalid HTTP chunked body Ungültiger HTTP Chunked-Body QIODevice Permission denied Zugriff verweigert Too many open files Zu viele Dateien geöffnet No such file or directory Die Datei oder das Verzeichnis konnte nicht gefunden werden No space left on device Kein freier Speicherplatz auf dem Gerät vorhanden Unknown error Unbekannter Fehler QInputContext XIM XIM XIM input method XIM-Eingabemethode Windows input method Windows-Eingabemethode Mac OS X input method Mac OS X-Eingabemethode QInputDialog OK OK Cancel Abbrechen QLineEdit Clear Löschen Select All Alles auswählen &Undo &Rückgängig &Redo Wieder&herstellen Cu&t &Ausschneiden &Copy &Kopieren &Paste Einf&ügen Delete Löschen QLineEditPrivate &Undo &Rückgängig &Redo Wieder&herstellen Cu&t &Ausschneiden &Copy &Kopieren &Paste Einf&ügen Delete Löschen Select All Alles auswählen QLocalFs Could not rename %1 to %2 Konnte nicht umbenannt werden: %1 nach %2 Could not open %1 Konnte nicht geöffnet werden: %1 Could not write %1 Konnte nicht geschrieben werden: %1 Could not read directory %1 Konnte Verzeichnis nicht lesen %1 Could not create directory %1 Konnte Verzeichnis nicht erstellen %1 Could not remove file or directory %1 Konnte Datei oder Verzeichnis nicht löschen %1 QMainWindow Line up Ausrichten Customize... Anpassen... QMenuBar About Info Config Konfiguration Preference Einstellungen Options Optionen Setting Einstellungen Setup Einrichten Quit Beenden Exit Beenden QMessageBox OK OK Cancel Abbrechen &Yes &Ja &No N&ein &Abort &Abbrechen &Retry &Wiederholen &Ignore &Ignorieren <h3>About Qt</h3><p>This application was created with Qt version %1.</p> <h3>Über Qt</h3><p>Dieses Programm wurde mit der Qt Version %1 erstellt.</p> <p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform GUI &amp; application development.</p><p>Qt provides single-source portability across Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX and many other versions of Unix with X11.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>Dieses Programm verwendet Qt Version %1</p><p>Qt ist ein multi-platform Framework zum Erstellen von GUI-Programmen in C++.</p><p>Qt bietet Portierungsmöglichkeiten mit nur einer Quellcode-Basis auf Windows 95/98/NT/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX und vielen anderen Unix-Versionen, die X11 verwenden.<br>Qt ist auch für eingebettete Systeme erhältlich.</p><p>Qt ist ein Produkt von Trolltech. Weitere Informationen finden Sie unter <tt>http://www.trolltech.com/qt/</tt>.</p> <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform GUI &amp; application development.</p><p>Qt provides single-source portability across Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX and many other versions of Unix with X11.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>Über Qt</h3><p>Dieses Programm verwendet Qt Version %1</p><p>Qt ist ein multi-platform Framework zum Erstellen von GUI-Programmen in C++.</p><p>Qt bietet Portierungsmöglichkeiten mit nur einer Quellcode-Basis auf Windows 95/98/NT/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX und vielen anderen Unix-Versionen, die X11 verwenden.<br>Qt ist auch für eingebettete Systeme erhältlich.</p><p>Qt ist ein Produkt von Trolltech. Weitere Informationen finden Sie unter <tt>http://www.trolltech.com/qt/</tt>.</p> <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for multiplatform GUI &amp; application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>Über Qt</h3><p>Dieses Programm verwendet Qt Version %1</p><p>Qt ist ein multi-platform Framework zum Erstellen von GUI-Programmen in C++.</p><p>Qt bietet Portierungsmöglichkeiten mit nur einer Quellcode-Basis auf MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux und allen anderen großen kommerziellen Unix-Versionen.<br>Qt ist auch für eingebettete Systeme erhältlich.</p><p>Qt ist ein Produkt von Trolltech. Weitere Informationen finden Sie unter <tt>http://www.trolltech.com/qt/</tt>.</p> Yes to &All Ja zu &allem N&o to All N&ein zu allem About Qt Über Qt Help Hilfe <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>Über Qt</h3>%1<p>Qt ist ein plattformübergreifendes C++-Framework zum Erstellen von Programmen.</p><p>Qt macht es möglich mit nur einer einzigen Quellcode-Basis Programme für verschiedene Plattformen wie MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux und alle wichtigen Unix-Versionen zu erstellen. Mit Qtopia Core ist Qt auch für eingebettete Systeme erhältlich.</p><p>Qt ist ein Produkt von Trolltech. Weitere Informationen finden Sie unter <tt>http://www.trolltech.com/qt/</tt>.</p> <p>This program uses Qt version %1.</p> <p>Dieses Programm verwendet Qt Version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> <p>Dieses Programm verwendet Qt Open Source Edition Version %1.</p><p>Die Qt Open Source Edition ist bestimmt für die Entwicklung von Open-Source-Programmen. Wenn Sie proprietäre (Closed Source) Software entwickeln brauchen Sie eine komerzielle Qt-Lizenz.</p><p>Um mehr über das Lizenzsystem von Qt zu erfahren besuchen Sie die Seite <tt>http://www.trolltech.com/company/model.html</tt>.</p> QNativeSocketEngine The remote host closed the connection Der entfernte Rechner schloss die Verbindung Network operation timed out Das Zeitlimit für die Operation wurde überschritten Out of resources Keine Resourcen verfügbar Unsupported socket operation Nichtunterstütztes Socket-Kommando Protocol type not supported Das Protokoll wird nicht unterstützt Invalid socket descriptor Ungültiger Socket-Deskriptor Network unreachable Das Netzwerk ist nicht erreichbar Permission denied Zugriff verweigert Connection timed out Das Zeitlimit für die Verbindung wurde überschritten Connection refused Verbindung verweigert The bound address is already in use Die angegebene Adresse ist bereits in Gebrauch The address is not available Die Adresse ist nicht verfügbar The address is protected Die Adresse ist geschützt Datagram was to large to send Das Datagramm war zu groß um gesendet zu werden Unable to send a message Die Nachricht konnte nicht gesendet werden Unable to receive a message Die Nachricht konnte nicht empfangen werden Unable to write Der Schreibvorgang konnte nicht ausgeführt werden Network error Netzwerkfehler Another socket is already listening on the same port Ein anderer Socket hört bereits auf denselben Port Unable to initialize non-blocking socket Der nichtblockierende Socket konnte nicht initialisiert werden Unable to initialize broadcast socket Der Broadcast-Socket konnte nicht initialisiert werden Attempt to use IPv6 socket on a platform with no IPv6 support Es wurde versucht einen IPv6-Socket auf einem System ohne IPv6-Unterstützung zu verwenden QNetworkProtocol Operation stopped by the user Operation von Benutzer angehalten QObject All Files (*) Alle Dateien (*) All Files (*.*) Alle Dateien (*.*) Open Öffnen Save As Speichern unter Open Öffnen Select a Directory Wählen Sie ein Verzeichnis Drive Laufwerk File Datei Directory Verzeichnis Symbolic Link Verknüpfung Unknown Unbekannt False Falsch True Wahr QPageSetupDialog OK OK Cancel Abbrechen Portrait Hochformat Landscape Querformat QPrintDialog locally connected direkt verbunden Aliases: %1 Alias: %1 unknown unbekannt Unknown Location Unbekannte Adresse OK OK Cancel Abbrechen Printer settings Drucker-Einstellungen Print in color if available Farbig drucken falls möglich Print in grayscale Als Graustufen drucken Print destination Drucker Print to printer: Auf Drucker drucken: Printer Drucker Host Rechner Comment Kommentar Print to file: Drucken in Datei: Browse... Durchsuchen... Options Optionen Print all Alles drucken Print range Bereich drucken From page: Von Seite: To page: Bis Seite: Print first page first Erste Seite zuerst drucken Print last page first Letzte Seite zuerst drucken Number of copies: Anzahl der Kopien: Paper format Papierformat Portrait Hochformat Landscape Querformat A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A4 (210x297 mm, 8.26x11.7 inches) A4 (210 x 297 mm, 8,26 x 11,7 Zoll) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B4 (250 x 353 mm) B5 (176 x 250 mm, 6.93x9.84 inches) B5 (176 x 250 mm, 6.93 x 9.84 Zoll) B6 (125 x 176 mm) B6 (125 x 176 mm) B7 (88 x 125 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Executive (7.5x10 inches, 191x254 mm) Executive (7,5 x 10 Zoll, 191 x 254 mm) Folio (210 x 330 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Legal (8.5x14 inches, 216x356 mm) Legal (8,5 x 14 Zoll, 216 x 356 mm) Letter (8.5x11 inches, 216x279 mm) Letter (8,5 x 11 Zoll, 216 x 279 mm) Tabloid (279 x 432 mm) Tabloid (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) US Common #10 Envelope (105 x 241 mm) Setup Printer Drucker-Einstellungen PostScript Files (*.ps);;All Files (*) PostScript-Dateien (*.ps);;Alle Dateien (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) A4 (210 x 297 mm) B5 (176 x 250 mm, 6.93 x 9.84 inches) B5 (176 x 250 mm) Executive (7.5 x 10 inches, 191 x 254 mm) Executive (7,5 x 10 Zoll, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Legal (8,5 x 14 Zoll, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Letter (8,5 x 11 Zoll, 216 x 279 mm) Print selection Die Selektion Drucken Page size: Seitengröße: Orientation: Druckausrichtung: Paper source: Papierquelle: QPrintDialogPrivate Printer settings Drucker-Einstellungen Print in color if available Farbig drucken falls möglich Print in grayscale Als Graustufen drucken Print destination Drucker Print to printer: Auf Drucker drucken: Print to file: Drucken in Datei: Browse... Durchsuchen... Options Optionen Print all Alles drucken Print range Bereich drucken From page: Von Seite: To page: Bis Seite: Print first page first Erste Seite zuerst drucken Print last page first Letzte Seite zuerst drucken Number of copies: Anzahl der Kopien: Paper format Papierformat Portrait Hochformat Landscape Querformat PostScript Files (*.ps);;All Files (*) PostScript-Dateien (*.ps);;Alle Dateien (*) OK OK Cancel Abbrechen QProcess Unknown error Unbekannter Fehler QProgressBar %1% %1 % QProgressDialog Cancel Abbrechen QRegExp no error occurred kein Fehler disabled feature used nicht aktivierte Eigenschaft wurde benutzt bad char class syntax falsche Syntax für Zeichen Klasse bad lookahead syntax falsche Syntax für Lookahead bad repetition syntax falsche Syntax für Wiederholungen invalid octal value ungültiger Oktal-Wert missing left delim fehlende linke Begrenzung unexpected end unerwartetes Ende met internal limit internes Limit erreicht QScrollBar Scroll here Hier scrollen Left edge Linke Seite Top Anfang Right edge Rechte Seite Bottom Ende Page left Eine Seite nach links Page up Eine Seite nach oben Page right Eine Seite nach rechts Page down Eine Seite nach unten Scroll left Nach links scrollen Scroll up Nach oben scrollen Scroll right Nach rechts scrollen Scroll down Nach unten scrollen QShortcut Space Leertaste Esc Esc Tab Tab Backtab Rück-Tab Backspace Rücktaste Return Return Enter Enter Ins Einfg Del Entf Pause Pause Print Druck SysReq SysReq Home Pos1 End Ende Left Links Up Hoch Right Rechts Down Runter PgUp Bild aufwärts PgDown Bild abwärts CapsLock Feststelltaste NumLock Zahlen-Feststelltaste ScrollLock Rollen-Feststelltaste Menu Menü Help Hilfe Back Zurück Forward Vorwärts Stop Abbrechen Refresh Aktualisieren Volume Down Lautstärke - Volume Mute Ton aus Volume Up Lautstärke + Bass Boost Bass Boost Bass Up Bass + Bass Down Bass - Treble Up Höhen + Treble Down Höhen - Media Play Wiedergabe Media Stop Stopp Media Previous Vorheriger Media Next Nächster Media Record Aufzeichnen Favorites Favoriten Search Suchen Standby Standby Open URL Öffne URL Launch Mail Start Mail Launch Media Start Media Player Launch (0) Start (0) Launch (1) Start (1) Launch (2) Start (2) Launch (3) Start (3) Launch (4) Start (4) Launch (5) Start (5) Launch (6) Start (6) Launch (7) Start (7) Launch (8) Start (8) Launch (9) Start (9) Launch (A) Start (A) Launch (B) Start (B) Launch (C) Start (C) Launch (D) Start (D) Launch (E) Start (E) Launch (F) Start (F) Print Screen Bildschirm drucken Page Up Bild aufwärts Page Down Bild abwärts Caps Lock Feststelltaste Num Lock Zahlen-Feststelltaste Number Lock Zahlen-Feststelltaste Scroll Lock Rollen-Feststelltaste Insert Einfügen Delete Löschen Escape Escape System Request System Request Select Auswählen Yes Ja No Nein Context1 Kontext1 Context2 Kontext2 Context3 Kontext3 Context4 Kontext4 Call Anruf Hangup Auflegen Flip Umdrehen Ctrl Strg Shift Umschalt Alt Alt Meta Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server Die Socks5-Verbindung zu einen Socks-Server hat das Zeitlimit überschritten QSql Delete Löschen Delete this record? Diesen Datensatz löschen? Yes Ja No Nein Insert Einfügen Update Aktualisieren Save edits? Änderungen speichern? Cancel Abbrechen Confirm Bestätigen Cancel your edits? Änderungen verwerfen? QTabDialog OK OK Apply Anwenden Help Hilfe Defaults Defaults Cancel Abbrechen QTcpServer Socket operation unsupported Nichtunterstütztes Socket-Kommando QTextEdit Clear Löschen Select All Alles auswählen &Undo &Rückgängig &Redo Wieder&herstellen Cu&t &Ausschneiden &Copy &Kopieren &Paste Einf&ügen Delete Löschen QTitleBar System Menu System-Menü Shade Aufrollen Unshade Herabrollen Normalize Wiederherstellen Minimize Minimieren Maximize Maximieren Close Schließen QToolBar More... Mehr... QUdpSocket This platform does not support IPv6 Diese Plattform unterstützt kein IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark LRM Left-to-right mark RLM Right-to-left mark RLM Right-to-left mark ZWJ Zero width joiner ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWNJ Zero width non-joiner ZWSP Zero width space ZWSP Zero width space LRE Start of left-to-right embedding LRE Start of left-to-right embedding RLE Start of right-to-left embedding RLE Start of right-to-left embedding LRO Start of left-to-right override LRO Start of left-to-right override RLO Start of right-to-left override RLO Start of right-to-left override PDF Pop directional formatting PDF Pop directional formatting Insert Unicode control character Unicode-Kontrollzeichen einfügen QUrlOperator The protocol `%1' is not supported Das Protokoll `%1' wird nicht unterstützt The protocol `%1' does not support listing directories Das Protokoll "%1" wird nicht unterstützt oder es "%2" unterstützt nicht die Auflistung von Verzeichnissen The protocol `%1' does not support creating new directories Das Protokoll `%1' unterstützt nicht das Anlegen neuer Verzeichnisse The protocol `%1' does not support removing files or directories Das Protokoll `%1' untersützt nicht das Löschen von Dateien oder Verzeichnissen The protocol `%1' does not support renaming files or directories Das Protokoll `%1' untersützt nicht das Umbenennen von Dateien oder Verzeichnissen The protocol `%1' does not support getting files Das Protokoll `%1' untersützt nicht das Laden von Files The protocol `%1' does not support putting files Das Protokoll `%1' untersützt nicht das Speichern von Files The protocol `%1' does not support copying or moving files or directories Das Protokoll `%1' untersützt nicht das Kopieren oder Verschieben von Dateien oder Verzeichnissen (unknown) (unbekannt) QWSDecoration &Restore Wieder&herstellen &Move Ver&schieben &Size &Größe Mi&nimize M&inimieren Ma&ximize Ma&ximieren Close Schließen Windows Windows KDE KDE KDE2 KDE2 Hydro Hydro Default Standard BeOS BeOS QWSManager Style Stil QWhatsThisAction What's This? Direkthilfe QWhatsThisButton What's this? Direkthilfe QWidget * * QWizard Cancel Abbrechen < Back < Zurück Next > Weiter > Finish Abschließen Help Hilfe &Cancel &Abbrechen < &Back < &Zurück &Next > &Weiter > &Finish Ab&schließen &Help &Hilfe QWorkspace &Restore Wieder&herstellen &Move Ver&schieben &Size &Größe ändern Mi&nimize M&inimieren Ma&ximize Ma&ximieren &Close Schl&ießen Stay on &Top Im &Vordergrund bleiben Minimize Minimieren Restore Down Wiederherstellen Close Schließen Sh&ade &Aufrollen %1 - [%2] %1 - [%2] &Unshade &Herabrollen QWorkspacePrivate &Restore Wieder&herstellen &Move Ver&schieben Mi&nimize M&inimieren Ma&ximize Ma&ximieren &Close Schl&ießen Stay on &Top Im &Vordergrund bleiben Sh&ade &Aufrollen %1 - [%2] %1 - [%2] Minimize Minimieren Restore Down Wiederherstellen Close Schließen &Unshade &Herabrollen QXml no error occurred kein Fehler error triggered by consumer Konsument löste Fehler aus unexpected end of file unerwartetes Ende der Datei more than one document type definition mehr als eine Dokumenttypdefinition error occurred while parsing element Fehler beim Parsen eines Elements tag mismatch Element-Tags sind nicht richtig geschachtelt error occurred while parsing content Fehler beim Parsen des Inhalts eines Elements unexpected character unerwartetes Zeichen invalid name for processing instruction ungültiger Namer für eine Processing-Instruktion version expected while reading the XML declaration fehlende Version beim Parsen der XML-Deklaration wrong value for standalone declaration falscher Wert für die Standalone-Deklaration error occurred while parsing document type definition Fehler beim Parsen der Dokumenttypdefinition letter is expected ein Buchstabe ist an dieser Stelle erforderlich error occurred while parsing comment Fehler beim Parsen eines Kommentars error occurred while parsing reference Fehler beim Parsen einer Referenz internal general entity reference not allowed in DTD interne allgeimeine Entity-Referenz ist nicht erlaubt in der DTD external parsed general entity reference not allowed in attribute value externe Entity-Referenz is nicht erlaubt in einem Attribut-Wert external parsed general entity reference not allowed in DTD externe Entity-Referenz ist nicht erlaubt in der DTD unparsed entity reference in wrong context nicht-analysierte Entity-Referenz im falschen Kontext verwendet recursive entities rekursive Enitity error in the text declaration of an external entity Fehler in der Text-Deklaration einer externen Entity encoding declaration or standalone declaration expected while reading the XML declaration fehlende Encoding-Deklaration oder Standalone-Deklaration beim Parsen der XML-Deklaration standalone declaration expected while reading the XML declaration fehlende Standalone-Deklaration beim Parsen der XML Deklaration QtMultiLineEdit Undo Rückgängig Redo Wiederherstellen Cut Ausschneiden Copy Kopieren Paste Einfügen Paste special... Einfügen spezial... Clear Löschen Select All Alles auswählen mm3d-master/i18n/qt_fr.ts000066400000000000000000002204751324021725400154630ustar00rootroot00000000000000 Q3Accel %1, %2 not defined La séquence %1, %2 n'est pas définie Ambiguous %1 not handled Séquence ambiguë %1 non traitée Q3DataTable True Vrai False Faux Insert Insérer Update Actualiser Delete Supprimer Q3FileDialog Copy or Move a File Copie ou déplace un fichier Read: %1 Lecture : %1 Write: %1 Écriture : %1 Cancel Annuler All Files (*) Tous les fichiers (*) Name Nom Size Taille Type Type Date Date Attributes Attributs &OK &OK Look &in: Chercher &dans : File &name: &Nom de fichier : File &type: &Type de fichier : Back Précédent (historique) One directory up Aller au dossier parent Create New Folder Créer un nouveau dossier List View Affichage liste Detail View Affichage détaillé Preview File Info Informations du fichier prévisualisé Preview File Contents Contenu du fichier prévisualisé Read-write Lecture-écriture Read-only Lecture seule Write-only Écriture seule Inaccessible Inaccessible Symlink to File Lien symbolique vers un fichier Symlink to Directory Lien symbolique vers un dossier Symlink to Special Lien symbolique vers un fichier spécial File Fichier Dir Dossier Special Fichier spécial Open Ouvrir Save As Enregistrer sous &Open &Ouvrir &Save &Enregistrer &Rename &Renommer &Delete Suppri&mer R&eload R&echarger Sort by &Name Trier par &nom Sort by &Size Trier par ta&ille Sort by &Date Trier par &date &Unsorted &Non trié Sort Tri Show &hidden files Afficher les fic&hiers cachés the file le fichier the directory le dossier the symlink le lien symbolique Delete %1 Supprimer %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Voulez-vous vraiment supprimer %1 "%2"?</qt> &Yes &Oui &No &Non New Folder 1 Nouveau dossier 1 New Folder Nouveau dossier New Folder %1 Nouveau dossier %1 Find Directory Chercher dans le dossier Directories Dossiers Directory: Dossier : Error Erreur %1 File not found. Check path and filename. %1 Impossible de trouver le fichier. Vérifier le chemin et le nom du fichier. All Files (*.*) Tous les fichiers (*.*) Open Ouvrir Select a Directory Sélectionner un dossier Q3LocalFs Could not read directory %1 Impossible de lire le dossier %1 Could not create directory %1 Impossible de créer le dossier %1 Could not remove file or directory %1 Impossible de supprimer le fichier ou dossier %1 Could not rename %1 to %2 Impossible de renommer %1 en %2 Could not open %1 Impossible d'ouvrir %1 Could not write %1 Impossible d'écrire %1 Q3MainWindow Line up Aligner Customize... Personnaliser... Q3NetworkProtocol Operation stopped by the user Opération interrompue par l'utilisateur Q3ProgressDialog Cancel Annuler Q3TabDialog OK OK Apply Appliquer Help Aide Defaults Par défaut Cancel Annuler Q3TextEdit &Undo &Annuler &Redo A&nnuler Annuler Cu&t Co&uper &Copy Cop&ier &Paste Co&ller Clear Effacer Select All Tout sélectionner Q3ToolBar More... Reste... Q3UrlOperator The protocol `%1' is not supported Le protocole '%1' n'est pas géré The protocol `%1' does not support listing directories Le protocole `%1' ne permet pas de lister les fichiers d'un dossier The protocol `%1' does not support creating new directories Le protocole `%1' ne permet pas de créer de nouveaux dossiers The protocol `%1' does not support removing files or directories Le protocole `%1' ne permet pas de supprimer des fichiers ou des dossiers The protocol `%1' does not support renaming files or directories Le protocole `%1' ne permet pas de renommer des fichiers ou des dossiers The protocol `%1' does not support getting files Le protocole `%1' ne permet pas de recevoir des fichiers The protocol `%1' does not support putting files Le protocole `%1' ne permet pas d'envoyer des fichiers The protocol `%1' does not support copying or moving files or directories Le protocole `%1' ne permet pas de copier ou de déplacer des fichiers (unknown) (inconnu) Q3Wizard &Cancel &Annuler < &Back < &Précédent &Next > &Suivant > &Finish &Terminer &Help &Aide QAbstractSocket Host not found Hôte introuvable Connection refused Connexion refusée Socket operation timed out Opération socket expirée QAbstractSpinBox &Step up &Augmenter Step &down &Diminuer QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. LTR Executable '%1' requires Qt %2, found Qt %3. L'exécutable '%1' requiert Qt %2 (Qt %3 présent). Incompatible Qt Library Error Erreur : bibliothèque Qt incompatible Activate Activer Activates the program's main window Active la fenêtre principale du programme QColorDialog Hu&e: &Teinte : &Sat: &Saturation : &Val: &Luminance : &Red: &Rouge : &Green: &Vert : Bl&ue: Ble&u : A&lpha channel: Canal a&lpha : &Basic colors Couleurs de &base &Custom colors &Couleurs personnalisées &Define Custom Colors >> Définir des &couleurs personnalisées >> OK OK Cancel Annuler &Add to Custom Colors &Ajouter aux couleurs personnalisées Select color Sélection d'une couleur QDateTimeEdit AM AM am am PM PM pm pm QDialog What's This? Qu'est-ce que c'est ? QDialogButtons Yes to All Oui à tout OK to All OK à tout No to All Non à tout Cancel All Tout annuler Yes Oui OK OK No Non Cancel Annuler Apply Appliquer Ignore Ignorer Retry Réessayer Abort Abandonner Help Aide %1 to All %1 à tout QDirModel Name Nom Size Taille Type Type Modified Modifié QErrorMessage &Show this message again &Afficher ce message de nouveau &OK &OK Debug Message: Message de débogage: Warning: Avertissement: Fatal Error: Erreur fatale: QFileDialog Cancel Annuler Back Précédent (historique) Create New Folder Créer un nouveau dossier List View Affichage liste Detail View Affichage détaillé Open Ouvrir &Open &Ouvrir &Save &Enregistrer &Rename &Renommer &Delete Suppri&mer Sort by &Name Trier par &nom Sort by &Size Trier par ta&ille Sort by &Date Trier par &date &Unsorted &Non trié Sort Tri Show &hidden files Afficher les fic&hiers cachés Directories Dossiers Save Enregistrer All Files (*) Tous les fichiers (*) %1 already exists. Do you want to replace it? Le fichier %1 existe déjà. Voulez-vous l'écraser ? %1 File not found. Please verify the correct file name was given. %1 Fichier introuvable. Veuillez vérifier que le nom du fichier est correct. My Computer Mon ordinateur &Reload &Recharger Parent Directory Dossier parent Look in: Chercher dans : File name: Nom de fichier : Files of type: Fichiers de type : QFileDialogPrivate %1 Directory not found. Please verify the correct directory name was given. %1 Dossier introuvable. Veuillez vérifier que le nom du dossier est correct. QFontDialog &Font &Police Font st&yle St&yle de police &Size &Taille Effects Effets Stri&keout &Barré &Underline &Souligné Sample Exemple OK OK Apply Appliquer Cancel Annuler Close Fermer Select Font Choisir une police Wr&iting System &Système d'écriture QFtp Host %1 found Hôte %1 trouvé Host found Hôte trouvé Connected to host %1 Connecté à l'hôte %1 Connected to host Connecté à l'hôte Connection to %1 closed Connexion à %1 arrêtée Connection closed Connexion arrêtée Host %1 not found Hôte %1 introuvable Connection refused to host %1 Connexion à l'hôte %1 refusée Unknown error Erreur inconnue Connecting to host failed: %1 Échec de la connexion à l'hôte %1 Login failed: %1 Échec du login: %1 Listing directory failed: %1 Échec du listage du dossier : %1 Changing directory failed: %1 Échec du changement de dossier : %1 Downloading file failed: %1 Échec du téléchargement du fichier : %1 Uploading file failed: %1 Échec du télédéchargement : %1 Removing file failed: %1 Échec de la suppression d'un fichier : %1 Creating directory failed: %1 Échec de la création d'un dossier : %1 Removing directory failed: %1 Échec de la suppression d'un dossier : %1 Not connected Non connecté Connection refused for data connection Connexion donnée refusée QHostInfo Unknown error Erreur inconnue QHostInfoAgent Host not found Hôte introuvable Unknown address type Adresse de type inconnu Unknown error Erreur inconnue QHttp Connection refused Connexion refusée Host %1 not found Hôte %1 introuvable Wrong content length Longueur du contenu invalide HTTP request failed Échec de la requête HTTP Host %1 found Hôte %1 trouvé Host found Hôte trouvé Connected to host %1 Connecté à l'hôte %1 Connected to host Connecté à l'hôte Connection to %1 closed Connexion à %1 arrêtée Connection closed Connexion arrêtée Unknown error Erreur inconnue Request aborted Requête interrompue No server set to connect to Aucun serveur spécifié Server closed connection unexpectedly Connexion interrompue par le serveur Invalid HTTP response header Entête de réponse HTTP invalide Invalid HTTP chunked body Fragment HTTP invalide QIODevice Permission denied Accès refusé Too many open files Trop de fichiers ouverts simultanément No such file or directory Aucun fichier ou dossier de ce nom No space left on device Aucun espace disponible sur le périphérique Unknown error Erreur inconnue QInputContext XIM XIM XIM input method Méthode d'entrée XIM Windows input method Méthode d'entrée Windows Mac OS X input method Méthode d'entrée Mac OS X QInputDialog OK OK Cancel Annuler QLineEdit Select All Tout sélectionner &Undo &Annuler &Redo A&nnuler Annuler Cu&t Co&uper &Copy Cop&ier &Paste Co&ller Delete Supprimer QMessageBox OK OK Cancel Annuler &Yes &Oui &No &Non &Abort &Abandonner &Retry &Réessayer &Ignore &Ignorer Yes to &All Oui à &tout N&o to All Non à to&ut About Qt À propos de Qt Help Aide <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>À propos de Qt</h3>%1<p>Qt est une boîte à outils C++ pour le développement multi-plateforme d'applications graphiques.</p><p>Qt permet de porter un même source code sur MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux ainsi que les principales versions Unix commerciales. Qt est aussi disponible pour les systèmes embarqués sous le nom de Qtopia Core.</p><p>Qt est un produit de Trolltech. Consultez <tt>http://www.trolltech.com/qt/</tt> pour de plus amples renseignements.</p> <p>This program uses Qt version %1.</p> <p>Ce programme utilise la version %1 de Qt.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> <p>Ce programme utilise l'édition Open Source de Qt version %1.</p><p>L'édition Open Source de Qt est destinée au développement de programmes Open Source. Si vous désirez écrire des applications commerciales (code source fermé), vous devez posséder une licence Qt commerciale.</p><p>Veuillez consulter <tt>http://www.trolltech.com/company/model.html</tt> pour un aperçu des licences applicables à Qt.</p> QNativeSocketEngine The remote host closed the connection L'hôte distant a fermé la connexion Network operation timed out L'opération réseau a expiré Out of resources Manque de ressources Unsupported socket operation Opération socket non supportée Protocol type not supported Protocol non géré Invalid socket descriptor Descripteur de socket invalide Network unreachable Réseau impossible à rejoindre Permission denied Accès refusé Connection timed out Connexion expirée Connection refused Connexion refusée The bound address is already in use L'adresse liée est déjà en usage The address is not available L'adresse n'est pas disponible The address is protected L'adresse est protégée Datagram was to large to send Le datagramme est trop gros pour pouvoir être envoyé Unable to send a message Impossible d'envoyer un message Unable to receive a message Impossible de recevoir un message Unable to write Impossible d'écrire Network error Erreur réseau Another socket is already listening on the same port Un autre socket écoute déjà sur le même port Unable to initialize non-blocking socket Impossible d'initialiser le socket asynchrone Unable to initialize broadcast socket Impossible d'initialiser le socket broadcast Attempt to use IPv6 socket on a platform with no IPv6 support Tentative d'utiliser un socket IPv6 sur une plateforme qui ne supporte pas IPv6 QObject All Files (*) Tous les fichiers (*) All Files (*.*) Tous les fichiers (*.*) Open Ouvrir Save As Enregistrer sous Open Ouvrir Select a Directory Sélectionner un dossier Drive Unité File Fichier Directory Dossier Symbolic Link Lien symbolique Unknown Inconnu False Faux True Vrai QPrintDialog locally connected connecté en local unknown inconnu Unknown Location Emplacement inconnu OK OK Cancel Annuler Printer settings Configuration de l'impression Print in color if available Imprimer en couleur si possible Print in grayscale Imprimer en niveaux de gris Print destination Type d'impression Print to printer: Imprimer avec l'imprimante : Print to file: Imprimer dans un fichier : Browse... Parcourir... Options Options Print all Imprimer tout Print range Imprimer la sélection From page: De la page : To page: À la page : Print first page first Imprimer d'abord la première page Print last page first Imprimer d'abord la dernière page Number of copies: Nombre de copies : Paper format Format du papier Portrait Portrait Landscape Paysage A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B4 (250 x 353 mm) B6 (125 x 176 mm) B6 (125 x 176 mm) B7 (88 x 125 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Folio (210 x 330 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Tabloid (279 x 432 mm) Tabloïde (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) US Common #10 Envelope (105 x 241 mm) Aliases: %1 Alias : %1 PostScript Files (*.ps);;All Files (*) Fichiers PostScript (*.ps);;Tous les fichiers (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) A4 (210 x 297 mm) B5 (176 x 250 mm, 6.93 x 9.84 inches) B5 (176 x 250 mm) Executive (7.5 x 10 inches, 191 x 254 mm) Executive (7,5 x 10 pouces, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Legal (8.5 x 14 pouces, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Letter (8,5 x 11 pouces, 216 x 279 mm) Print selection Imprimer la sélection Page size: Dimensions : Orientation: Orientation : Paper source: Source du papier : QProcess Unknown error Erreur inconnue QProgressBar %1% %1 % QProgressDialog Cancel Annuler QRegExp no error occurred aucune erreur ne s'est produite disabled feature used option désactivée bad char class syntax syntaxe invalide pour classe de caractère bad lookahead syntax syntaxe invalide pour lookahead bad repetition syntax syntaxe invalide pour répétition invalid octal value valeur octale invalide missing left delim délémiteur gauche manquant unexpected end fin impromptue met internal limit rencontré limite interne QScrollBar Scroll here Défiler jusqu'ici Left edge Extrême gauche Top En haut Right edge Extrême droite Bottom En bas Page left Page précédente Page up Page précédente Page right Page suivante Page down Page suivante Scroll left Défiler vers la gauche Scroll up Défiler vers le haut Scroll right Défiler vers la droite Scroll down Défiler vers le bas QShortcut Space Espace Esc Échap Tab Tab Backtab Tab arr Backspace Effacement Return Retour Enter Entrée Ins Inser Del Suppr Pause Pause Print Impr écran SysReq Syst Home Début End Fin Left Gauche Up Haut Right Droite Down Bas PgUp Page préc PgDown Page suiv CapsLock Verr maj NumLock Verr num ScrollLock Arrêt défil Menu Menu Help Aide Back Précédent (historique) Forward Successeur (historique) Stop Stop Refresh Rafraîchir Volume Down Volume bas Volume Mute Volume muet Volume Up Volume haut Bass Boost Graves fort Bass Up Graves haut Bass Down Graves bas Treble Up Aigus haut Treble Down Aigus bas Media Play Média démarrer Media Stop Média arrêt Media Previous Média précédent Media Next Média suivant Media Record Média enregistrer Favorites Préférés Search Recherche Standby Attente Open URL Ouvrir URL Launch Mail Lancer courrier Launch Media Lancer média Launch (0) Lancer (0) Launch (1) Lancer (1) Launch (2) Lancer (2) Launch (3) Lancer (3) Launch (4) Lancer (4) Launch (5) Lancer (5) Launch (6) Lancer (6) Launch (7) Lancer (7) Launch (8) Lancer (8) Launch (9) Lancer (9) Launch (A) Lancer (A) Launch (B) Lancer (B) Launch (C) Lancer (C) Launch (D) Lancer (D) Launch (E) Lancer (E) Launch (F) Lancer (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert Insérer Delete Supprimer Escape Échapement System Request Système Select Sélectionner Yes Oui No Non Context1 Contexte1 Context2 Contexte2 Context3 Contexte3 Context4 Contexte4 Call Appeler Hangup Raccrocher Flip Retourner Ctrl Ctrl Shift Maj Alt Alt Meta Méta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server Erreur d'expiration socks5 lors de l'établissement d'une connexion au serveur socks QSql Delete Supprimer Delete this record? Supprimer cet enregistrement ? Yes Oui No Non Insert Insérer Update Actualiser Save edits? Enregistrer les modifications ? Cancel Annuler Confirm Confirmer Cancel your edits? Annuler vos modifications ? QTcpServer Socket operation unsupported Operation socket non supportée QTextEdit Select All Tout sélectionner &Undo &Annuler &Redo A&nnuler Annuler Cu&t Co&uper &Copy Cop&ier &Paste Co&ller Delete Supprimer QUdpSocket This platform does not support IPv6 Cette plateforme ne supporte pas IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark LRM Left-to-right mark RLM Right-to-left mark RLM Right-to-left mark ZWJ Zero width joiner ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWNJ Zero width non-joiner ZWSP Zero width space ZWSP Zero width space LRE Start of left-to-right embedding LRE Start of left-to-right embedding RLE Start of right-to-left embedding RLE Start of right-to-left embedding LRO Start of left-to-right override LRO Start of left-to-right override RLO Start of right-to-left override RLO Start of right-to-left override PDF Pop directional formatting PDF Pop directional formatting Insert Unicode control character Insérer caractère de contrôle Unicode QWhatsThisAction What's This? Qu'est-ce que c'est ? QWidget * * QWorkspace &Restore &Restaurer &Move &Déplacer &Size &Redimensionner Mi&nimize Réd&uire Ma&ximize Ma&ximiser &Close &Fermer Stay on &Top &Rester au premier plan Minimize Réduire Restore Down Restaurer en bas Close Fermer Sh&ade &Enrouler %1 - [%2] %1 - [%2] &Unshade &Dérouler QXml no error occurred aucune erreur ne s'est produite error triggered by consumer erreur déclenchée par le consommateur unexpected end of file fin de fichier impromptue more than one document type definition plus d'une définition de type de document error occurred while parsing element une erreur s'est produite lors de l'analyse d'un élément tag mismatch balise débalancée error occurred while parsing content une erreur s'est produise lors de l'analyse du contenu unexpected character caractère impromptu invalid name for processing instruction nom d'instruction de traitement invalide version expected while reading the XML declaration version attendue dans la déclaration XML wrong value for standalone declaration valeur invalide pour déclaration autonome error occurred while parsing document type definition une erreur s'est produite lors de l'analyse d'une définition de type de document letter is expected lettre attendue error occurred while parsing comment une erreur s'est produise lors de l'analyse d'un commentaire error occurred while parsing reference une erreur s'est produite lors de l'analyse d'une référence internal general entity reference not allowed in DTD appel d'entité interne générale non permis dans la DTD external parsed general entity reference not allowed in attribute value appel d'entité externe parsée non permis dans la valeur d'un attribut external parsed general entity reference not allowed in DTD appel d'entité externe parsée générale non permis dans la DTD unparsed entity reference in wrong context appel d'entité non parsée dans un contexte invalide recursive entities entités récursives error in the text declaration of an external entity erreur dans la déclaration de texte d'une entité externe encoding declaration or standalone declaration expected while reading the XML declaration déclaration d'encodage ou déclaration autonome attendue dans la déclaration XML standalone declaration expected while reading the XML declaration déclaration autonome attendue dans la déclaration XML mm3d-master/i18n/qt_iw.ts000066400000000000000000003555271324021725400155020ustar00rootroot00000000000000 @default OK אישור Cancel ביטול Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True אמת False שקר Insert הוסף Update עדכן Delete מחק Q3FileDialog Copy or Move a File העתק או העבר קובץ Read: %1 קרא: %1 Write: %1 כתוב: %1 Cancel ביטול All Files (*) כל הקבצים (*) Name שם Size גודל Type סוג Date תאריך Attributes מאפיינים &OK &אישור Look &in: &חפש ב: File &name: &שם הקובץ: File &type: &סוג הקובץ: Back אחורה One directory up ספריה אחת למעלה Create New Folder צור תיקיה חדשה List View תצוגת רשימה Detail View תצוגת פרטים Preview File Info תצוגה מקדימה של פרטי הקובץ Preview File Contents תצוגה מקדימה של תוכן הקובץ Read-write קריאה-כתיבה Read-only קריאה-בלבד Write-only כתיבה-בלבד Inaccessible לא נגיש Symlink to File קישור סמלי לקובץ Symlink to Directory קישור סמלי לספריה Symlink to Special קישור סמלי לפריט מיוחד File קובץ Dir ספריה Special מיוחד Open פתח Save As שמירה בשם &Open &פתח &Save &שמור &Rename ש&נה שם &Delete &מחק R&eload &טען מחדש Sort by &Name סדר לפי ש&ם Sort by &Size סדר לפי &גודל Sort by &Date סדר לפי &תאריך &Unsorted &ללא סדר Sort סדר Show &hidden files הצג קבצים &מוסתרים the file הקובץ the directory הספריה the symlink הקישור הסמלי Delete %1 מחק את %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>האם אתה בטוח שברצונך למחוק %1 "%2"?</qt> &Yes &כן &No &לא New Folder 1 תיקיה חדשה 1 New Folder תיקיה חדשה New Folder %1 תיקיה חדשה %1 Find Directory חפש ספריה Directories ספריות Directory: Error שגיאה %1 File not found. Check path and filename. %1 הקובץ לא נמצא. בדוק את הנתיב ואת שם הקובץ. All Files (*.*) כל הקבצים (*.*) Open פתח Select a Directory בחר ספריה Q3Ftp Host %1 not found המארח %1 לא נמצא Connection refused to host %1 החיבור אל המארח %1 נדחה Connected to host %1 מחובר למארח %1 Connection closed החיבור נסגר Host %1 found המארח %1 נמצא Connection to %1 closed החיבור אל %1 נסגר Host found המארח נמצא Connected to host מחובר למארח Q3Http Wrong content length אורך תוכן שגוי Connection refused החיבור נדחה Host %1 not found המארח %1 לא נמצא HTTP request failed בקשת ה-HTTP נכשלה Host %1 found המארח %1 נמצא Connected to host %1 מחובר למארח %1 Connection to %1 closed החיבור אל %1 נסגר Host found המארח נמצא Connected to host מחובר למארח Connection closed החיבור נסגר Q3LocalFs Could not read directory %1 Could not create directory %1 Could not remove file or directory %1 Could not rename %1 to %2 לא ניתן לשנות את השם של %1 אל %2 Could not open %1 לא ניתן לפתוח את %1 Could not write %1 לא ניתן לכתוב את %1 Q3MainWindow Line up סדר בשורה Customize... התאמה אישית... Q3NetworkProtocol Operation stopped by the user הפעולה הופסקה על ידי המשתמש Q3ProgressDialog Cancel ביטול Q3TabDialog OK אישור Apply החל Help עזרה Defaults ברירות מחדל Cancel ביטול Q3TextEdit &Undo &בטל &Redo בצע &שוב Cu&t &גזור &Copy הע&תק &Paste ה&דבק Clear נקה Select All בחר הכל Q3ToolBar More... Q3UrlOperator The protocol `%1' is not supported הפרוטוקול "%1" אינו נתמך The protocol `%1' does not support listing directories הפרוטוקול "%1" לא תומך בהצגת ספריות The protocol `%1' does not support creating new directories הפרוטוקול "%1" לא תומך ביצירת ספריית חדשות The protocol `%1' does not support removing files or directories הפרוטוקול "%1" לא תומך בהסרת קבצים או ספריות The protocol `%1' does not support renaming files or directories הפרוטוקול "%1" לא תומך בשינוי שמותיהם של קבצים או ספריות The protocol `%1' does not support getting files הפרוטוקול "%1" לא תומך בהורדת קבצים The protocol `%1' does not support putting files הפרוטוקול "%1" לא תומך בהעלאת קבצים The protocol `%1' does not support copying or moving files or directories הפרוטוקול "%1" לא תומך בהעתקה או העברה של קבצים או ספריות (unknown) (לא ידוע) Q3Wizard &Cancel < &Back &Next > &Finish &Help QAbstractSocket Host not found Connection refused החיבור נדחה Socket operation timed out QAbstractSpinBox &Step up Step &down QAccel Space רווח Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print הדפס SysReq SysReq Home Home End End Left שמאלה Up למעלה Right ימינה Down למטה PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Ctrl Ctrl Alt Alt Shift Shift + + F%1 F%1 Help עזרה Back אחורה QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. RTL Executable '%1' requires Qt %2, found Qt %3. Incompatible Qt Library Error Activate Activates the program's main window QAquaStyle OK אישור Cancel ביטול QColorDialog Hu&e: &גוון: &Sat: &הרוויה: &Val: &ערך: &Red: &אדום: &Green: &ירוק: Bl&ue: &כחול: A&lpha channel: ע&רוץ אלפא: &Basic colors &צבעים בסיסיים &Custom colors צבעים &מותאמים אישית &Define Custom Colors >> &הגדר צבעים מותאמים אישית >> OK אישור Cancel ביטול &Add to Custom Colors ה&וסף לצבעים מותאמים אישית Select color בחירת צבע QDataManager Delete this record? האם למחוק רשומה זו? Yes כן No לא Save edits? האם לשמור את העריכה? Cancel ביטול Confirm אישור Cancel your edits? האם לבטל את העריכה שלך? QDataTable True אמת False שקר Insert הוסף Update עדכן Delete מחק QDateTimeEdit AM am PM pm QDialog What's This? מה זה? Help עזרה QDialogButtons Yes to All OK to All No to All Cancel All Yes כן OK אישור No לא Cancel ביטול Apply החל Ignore Retry Abort Help עזרה %1 to All QDirModel Name שם Size גודל Type סוג Modified QErrorMessage &Show this message again &הצג הודעה זו שנית &OK &אישור Debug Message: Warning: Fatal Error: QFileDialog Copy or Move a File העתק או העבר קובץ Read: %1 קרא: %1 Write: %1 כתוב: %1 Cancel ביטול All Files (*) כל הקבצים (*) Name שם Size גודל Type סוג Date תאריך Attributes מאפיינים OK אישור Look &in: &חפש ב: File &name: &שם הקובץ: File &type: &סוג הקובץ: Back אחורה One directory up ספריה אחת למעלה Create New Folder צור תיקיה חדשה List View תצוגת רשימה Detail View תצוגת פרטים Preview File Info תצוגה מקדימה של פרטי הקובץ Preview File Contents תצוגה מקדימה של תוכן הקובץ Read-write קריאה-כתיבה Read-only קריאה-בלבד Write-only כתיבה-בלבד Inaccessible לא נגיש Symlink to File קישור סמלי לקובץ Symlink to Directory קישור סמלי לספריה Symlink to Special קישור סמלי לפריט מיוחד File קובץ Dir ספריה Special מיוחד Open פתח Save As שמירה בשם &Open &פתח &Save &שמור &Rename ש&נה שם &Delete &מחק R&eload &טען מחדש Sort by &Name סדר לפי ש&ם Sort by &Size סדר לפי &גודל Sort by &Date סדר לפי &תאריך &Unsorted &ללא סדר Sort סדר Show &hidden files הצג קבצים &מוסתרים the file הקובץ the directory הספריה the symlink הקישור הסמלי Delete %1 מחק את %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>האם אתה בטוח שברצונך למחוק %1 "%2"?</qt> &Yes &כן &No &לא New Folder 1 תיקיה חדשה 1 New Folder תיקיה חדשה New Folder %1 תיקיה חדשה %1 Find Directory חפש ספריה Directories ספריות Save שמור Error שגיאה %1 File not found. Check path and filename. %1 הקובץ לא נמצא. בדוק את הנתיב ואת שם הקובץ. All Files (*.*) כל הקבצים (*.*) Open פתח Select a Directory בחר ספריה %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer &Reload Parent Directory Look in: File name: Files of type: QFileDialogPrivate Sort סדר &Open &פתח &Rename ש&נה שם &Delete &מחק Sort by &Name סדר לפי ש&ם Sort by &Size סדר לפי &גודל Sort by &Date סדר לפי &תאריך &Unsorted &ללא סדר Show &hidden files הצג קבצים &מוסתרים Back אחורה Create New Folder צור תיקיה חדשה List View תצוגת רשימה Detail View תצוגת פרטים Open פתח Cancel ביטול %1 Directory not found. Please verify the correct directory name was given. QFont Latin לטיני Greek יווניי Cyrillic קירילי Armenian ארמני Georgian גרוזיני Runic רוני Ogham Ogham Hebrew עברי Arabic ערבי Syriac סורי Thaana Thaana Devanagari דוואנגארי Bengali בנגלי Gurmukhi Gurmukhi Gujarati גוג'ראטי Oriya Oriya Tamil טמילי Telugu טלוגו Kannada Kannada Malayalam מלאי Sinhala ציילוני Thai תאילנדי Lao לאו Tibetan טיבטי Myanmar בורמזי Khmer קמבודי Han Han Hiragana Hiragana Katakana Katakana Hangul Hangul Bopomofo Bopomofo Yi Yi Ethiopic אתיופי Cherokee צ'ירוקי Canadian Aboriginal קנדי אבוריג'יני Mongolian מונגולית Currency Symbols סמלי מטבע Letterlike Symbols סמלי אותיות Number Forms צורות מספרים Mathematical Operators סמלים מתמטיים Technical Symbols סמלים טכניים Geometric Symbols סמלים הנדסיים Miscellaneous Symbols סמלים שונים Enclosed and Square תחום ומרובע Braille ברייל Unicode יוניקוד Reverse Oblique Reverse Oblique Reverse Italic נטוי הפוך Other אחר Oblique Oblique Italic נטוי Normal רגיל QFontDialog &Font &גופן Font st&yle &סגנון גופן &Size גו&דל Effects אפקטים Stri&keout קו &חוצה &Underline קו &תחתי &Color &צבע Sample דוגמה Scr&ipt &כתב OK אישור Apply החל Cancel ביטול Close סגור Select Font בחר גופן Wr&iting System QFtp Host %1 found המארח %1 נמצא Host found המארח נמצא Connected to host %1 מחובר למארח %1 Connected to host מחובר למארח Connection to %1 closed החיבור אל %1 נסגר Connection closed החיבור נסגר Login Incorrect הכניסה שגויה Host %1 not found המארח %1 לא נמצא Connection refused to host %1 החיבור אל המארח %1 נדחה Unknown error Connecting to host failed: %1 Login failed: %1 Listing directory failed: %1 Changing directory failed: %1 Downloading file failed: %1 Uploading file failed: %1 Removing file failed: %1 Creating directory failed: %1 Removing directory failed: %1 Not connected Connection refused for data connection QFtpPI Host %1 not found המארח %1 לא נמצא Connection refused to host %1 החיבור אל המארח %1 נדחה Connected to host %1 מחובר למארח %1 QHeader %1 %1 QHostInfo Unknown error QHostInfoAgent Host not found Unknown address type Unknown error QHttp Connection refused החיבור נדחה Host %1 not found המארח %1 לא נמצא Connection closed by %1 החיבור נסגר על ידי %1 Invalid HTTP reply header כותרת תשובה לא תקפה של HTTP Wrong content length אורך תוכן שגוי HTTP request failed בקשת ה-HTTP נכשלה Host %1 found המארח %1 נמצא Host found המארח נמצא Connected to host %1 מחובר למארח %1 Connected to host מחובר למארח Connection to %1 closed החיבור אל %1 נסגר Connection closed החיבור נסגר Unknown error Request aborted No server set to connect to Server closed connection unexpectedly Invalid HTTP response header Invalid HTTP chunked body QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK אישור Cancel ביטול QLineEdit &Undo &בטל &Redo בצע &שוב Cu&t &גזור &Copy הע&תק &Paste ה&דבק Clear נקה Select All בחר הכל Delete מחק QLineEditPrivate &Undo &בטל &Redo בצע &שוב Cu&t &גזור &Copy הע&תק &Paste ה&דבק Delete מחק Select All בחר הכל QLocalFs Could not rename %1 to %2 לא ניתן לשנות את השם של %1 אל %2 Could not open %1 לא ניתן לפתוח את %1 Could not write %1 לא ניתן לכתוב את %1 QMainWindow Line up סדר בשורה Customize... התאמה אישית... QMenuBar Options אפשרויות QMessageBox OK אישור Cancel ביטול &Yes &כן &No &לא &Abort &ביטול &Retry &נסה שנית &Ignore &התעלם <h3>About Qt</h3><p>This application was created with Qt version %1.</p> <div dir=rtl><h3>אודות Qt</h3></div><p dir=rtl>יישום זה נוצר באמצעות Qt גירסה %1.</p> <p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform GUI &amp; application development.</p><p>Qt provides single-source portability across Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX and many other versions of Unix with X11.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p dir=rtl>תוכנית זו עושה שימוש ב-Qt גירסה %1.</p><p dir=rtl>Qt הינה חבילת כלי ++C לפיתוח מרובה פלטפורמות של ממשקי משתמש גרפיים ויישומים.</p><p dir=rtl>Qt מספק ניידות קוד מקור בודד בין Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX וגירסאות רבות נוספות של יוניקס עם X11.<br>Qt זמין גם להתקנים מוטבעים.</p><p>Qt הינו מוצר של Trolltech product. עיין ב-<tt>http://www.trolltech.com/qt/</tt> למידע נוסף.</p> <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for cross-platform GUI &amp; application development.</p><p>Qt provides single-source portability across Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX and many other versions of Unix with X11.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <div dir=rtl><h3>אודות Qt</h3></div><p dir=rtl>תוכנית זו עושה שימוש ב-Qt גירסה %1.</p><p dir=rtl>Qt הינה חבילת כלי ++C לפיתוח מרובה פלטפורמות של ממשקי משתמש גרפיים ויישומים.</p><p dir=rtl>Qt מספק ניידות קוד מקור בודד בין Windows 95/98/NT4/ME/2000, Mac&nbsp;OS&nbsp;X, Linux, Solaris, HP-UX וגירסאות רבות נוספות של יוניקס עם X11.<br>Qt זמין גם להתקנים מוטבעים.</p><p>Qt הינו מוצר של Trolltech. עיין ב-<tt>http://www.trolltech.com/qt/</tt> למידע נוסף.</p> Yes to &All N&o to All About Qt Help עזרה <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused החיבור נדחה The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QNetworkProtocol Operation stopped by the user הפעולה הופסקה על ידי המשתמש QObject All Files (*) כל הקבצים (*) All Files (*.*) כל הקבצים (*.*) Open פתח Save As שמירה בשם Open פתח Select a Directory בחר ספריה Drive File קובץ Directory Symbolic Link Unknown False שקר True אמת QPageSetupDialog OK אישור Cancel ביטול Portrait לאורך Landscape לרוחב QPrintDialog locally connected מחוברת מקומית Aliases: %1 שמות נוספים: %1 unknown לא ידוע Unknown Location מיקום לא ידוע OK אישור Cancel ביטול Printer settings הגדרות מדפסת Print in color if available הדפס בצבע אם הדבר זמין Print in grayscale הדפס בגווני אפור Print destination יעד ההדפסה Print to printer: הדפס למדפסת: Printer מדפסת Host מארח Comment הערה Print to file: הדפס לקובץ: Browse... עיון... Options אפשרויות Print all הדפס הכל Print range טווח הדפסה From page: מעמוד: To page: עד עמוד: Print first page first הדפס את העמוד הראשון ראשון Print last page first הדפס את העמוד הראשון אחרון Number of copies: מספר עותקים: Paper format תבנית נייר Portrait לאורך Landscape לרוחב A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A4 (210x297 mm, 8.26x11.7 inches) A4 (210x297 mm, 8.26x11.7 inches) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B4 (250 x 353 mm) B5 (176 x 250 mm, 6.93x9.84 inches) B5 (176 x 250 mm, 6.93x9.84 inches) B6 (125 x 176 mm) B6 (125 x 176 mm) B7 (88 x 125 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Executive (7.5x10 inches, 191x254 mm) Executive (7.5x10 inches, 191x254 mm) Folio (210 x 330 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Legal (8.5x14 inches, 216x356 mm) Legal (8.5x14 inches, 216x356 mm) Letter (8.5x11 inches, 216x279 mm) Letter (8.5x11 inches, 216x279 mm) Tabloid (279 x 432 mm) Tabloid (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) US Common #10 Envelope (105 x 241 mm) Setup Printer הגדרות מדפסת PostScript Files (*.ps);;All Files (*) קבצי ps) PostScript.*);;כל הקבצים (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) B5 (176 x 250 mm, 6.93 x 9.84 inches) Executive (7.5 x 10 inches, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Print selection Page size: Orientation: Paper source: QPrintDialogPrivate Printer settings הגדרות מדפסת Print in color if available הדפס בצבע אם הדבר זמין Print in grayscale הדפס בגווני אפור Print destination יעד ההדפסה Print to printer: הדפס למדפסת: Print to file: הדפס לקובץ: Browse... עיון... Options אפשרויות Print all הדפס הכל Print range טווח הדפסה From page: מעמוד: To page: עד עמוד: Print first page first הדפס את העמוד הראשון ראשון Print last page first הדפס את העמוד הראשון אחרון Number of copies: מספר עותקים: Paper format תבנית נייר Portrait לאורך Landscape לרוחב PostScript Files (*.ps);;All Files (*) קבצי ps) PostScript.*);;כל הקבצים (*) OK אישור Cancel ביטול QProcess Unknown error QProgressBar %1% QProgressDialog Cancel ביטול QRegExp no error occurred לא אירעה כל שגיאה disabled feature used bad char class syntax bad lookahead syntax bad repetition syntax invalid octal value missing left delim unexpected end met internal limit QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space רווח Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print הדפס SysReq SysReq Home Home End End Left שמאלה Up למעלה Right ימינה Down למטה PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Menu Help עזרה Back אחורה Forward Stop Refresh Volume Down Volume Mute Volume Up Bass Boost Bass Up Bass Down Treble Up Treble Down Media Play Media Stop Media Previous Media Next Media Record Favorites Search Standby Open URL Launch Mail Launch Media Launch (0) Launch (1) Launch (2) Launch (3) Launch (4) Launch (5) Launch (6) Launch (7) Launch (8) Launch (9) Launch (A) Launch (B) Launch (C) Launch (D) Launch (E) Launch (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert הוסף Delete מחק Escape System Request Select Yes כן No לא Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl Ctrl Shift Shift Alt Alt Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete מחק Delete this record? האם למחוק רשומה זו? Yes כן No לא Insert הוסף Update עדכן Save edits? האם לשמור את העריכה? Cancel ביטול Confirm אישור Cancel your edits? האם לבטל את העריכה שלך? QTabDialog OK אישור Apply החל Help עזרה Defaults ברירות מחדל Cancel ביטול QTcpServer Socket operation unsupported QTextEdit &Undo &בטל &Redo בצע &שוב Cu&t &גזור &Copy הע&תק &Paste ה&דבק Clear נקה Select All בחר הכל Delete מחק QTitleBar System Menu תפריט מערכת Shade גלול Unshade בטל גלילה Normalize Normalize Minimize מזער Maximize הגדל Close סגור QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QUrlOperator The protocol `%1' is not supported הפרוטוקול "%1" אינו נתמך The protocol `%1' does not support listing directories הפרוטוקול "%1" לא תומך בהצגת ספריות The protocol `%1' does not support creating new directories הפרוטוקול "%1" לא תומך ביצירת ספריית חדשות The protocol `%1' does not support removing files or directories הפרוטוקול "%1" לא תומך בהסרת קבצים או ספריות The protocol `%1' does not support renaming files or directories הפרוטוקול "%1" לא תומך בשינוי שמותיהם של קבצים או ספריות The protocol `%1' does not support getting files הפרוטוקול "%1" לא תומך בהורדת קבצים The protocol `%1' does not support putting files הפרוטוקול "%1" לא תומך בהעלאת קבצים The protocol `%1' does not support copying or moving files or directories הפרוטוקול "%1" לא תומך בהעתקה או העברה של קבצים או ספריות (unknown) (לא ידוע) QWSDecoration &Restore ש&חזר &Move ה&זז &Size &שנה גודל Mi&nimize &מזער Ma&ximize &הגדל Close סגור Windows חלונות KDE KDE KDE2 KDE2 BeOS BeOS Hydro Hydro Default ברירת מחדל QWSManager Style סגנון QWhatsThisAction What's This? מה זה? QWhatsThisButton What's this? מה זה? QWidget * QWizard Cancel ביטול < Back < אחורה Next > קדימה > Finish סיום Help עזרה QWorkspace &Restore ש&חזר &Move ה&זז &Size &שנה גודל Mi&nimize &מזער Ma&ximize &הגדל &Close &סגור Stay on &Top &תמיד עליון Sh&ade &גלול %1 - [%2] %1 - [%2] Minimize מזער Restore Down שחזר למטה Close סגור &Unshade &בטל גלילה QWorkspacePrivate &Restore ש&חזר &Move ה&זז Mi&nimize &מזער Ma&ximize &הגדל &Close &סגור Stay on &Top &תמיד עליון Sh&ade &גלול %1 - [%2] %1 - [%2] Minimize מזער Restore Down שחזר למטה Close סגור &Unshade &בטל גלילה QXml no error occurred לא אירעה כל שגיאה error triggered by consumer נגרמה שגיאה על ידי הצרכן unexpected end of file סוף קובץ לא צפוי more than one document type definition יותר מהגדרה אחת של סוג מסמך error occurred while parsing element אירעה שגיאה בעת עיבוד המרכיב tag mismatch אי-התאמה בתגית error occurred while parsing content אירעה שגיאה בעת עיבוד התוכן unexpected character תו לא צפוי invalid name for processing instruction שם לא תקף עבור הוראת העיבוד version expected while reading the XML declaration הייתה צפויה גירסה בעת קריאה ההכרזה על XML wrong value for standalone declaration ערך שגוי עבור ההגדרה העצמאית encoding declaration or standalone declaration expected while reading the XML declaration הייתה צפויה הכרזה על קידוד או הכרזה עצמאית בעת קריאת ההכרזה על XML standalone declaration expected while reading the XML declaration הייתה צפויה הכרזה עצמאית בעת קריאת ההכרזה על XML error occurred while parsing document type definition אירעה שגיאה בעת עיבוד הגדרת סוג המסמך letter is expected הייתה צפויה אות error occurred while parsing comment אירעה שגיאה בעת עיבוד ההערה error occurred while parsing reference אירעה שגיאה בעת עיבוד ההתייחסות internal general entity reference not allowed in DTD התייחסות ליישות כללית פנימית אינה מותרת ב-DTD external parsed general entity reference not allowed in attribute value התייחסות ליישות כללית מעובדת חיצונית אינה מותרת בערך המאפיין external parsed general entity reference not allowed in DTD התייחסות ליישות כללית מעובדת חיצונית אינה מותרת ב-DTD unparsed entity reference in wrong context התייחסות ליישות לא מעובדת בהקשר שגוי recursive entities יישות רקורסיבית error in the text declaration of an external entity שגיאה בהכרזת טקסט של יישות חיצונית QtMultiLineEdit Undo בטל Redo שחזר Cut גזור Copy העתק Paste הדבק Paste special... הדבקה מיוחדת... Clear נקה Select All בחר הכל Transport Auth error mm3d-master/i18n/qt_ru.ts000066400000000000000000004037441324021725400155040ustar00rootroot00000000000000 Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True True False False Insert Вставить Update Обновить Delete Удалить Q3FileDialog Copy or Move a File Копировать или переместить файл Read: %1 Открытие: %1 Write: %1 Запись: %1 Cancel Отмена All Files (*) Все файлы (*) Name Имя Size Размер Type Тип Date Дата Attributes Атрибуты &OK &OK Look &in: &Смотреть в: File &name: &Имя файла: File &type: &Тип файла: Back Назад One directory up Вверх на один уровень Create New Folder Создать новый каталог List View Список Detail View Детальный вид Preview File Info Предпросмотр информации о файле Preview File Contents Предпросмотр содержимого файла Read-write Чтение-запись Read-only Только чтение Write-only Только запись Inaccessible Нет доступа Symlink to File Ссылка на файл Symlink to Directory Ссылка на каталог Symlink to Special Ссылка на спецфайл File Файл Dir Каталог Special Спецфайл Open Открыть Save As Сохранить как &Open &Открыть &Save &Сохранить &Rename &Переименовать &Delete &Удалить R&eload О&бновить Sort by &Name По &имени Sort by &Size По &размеру Sort by &Date По &дате &Unsorted &Не упорядочивать Sort Упорядочить Show &hidden files Показать &скрытые файлы the file файл the directory каталог the symlink ссылку Delete %1 Удалить %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Вы действительно хотите удалить %1 "%2"?</qt> &Yes &Да &No &Нет New Folder 1 Новый каталог 1 New Folder Новый каталог New Folder %1 Новый каталог %1 Find Directory Найти каталог Directories Каталоги Directory: Каталог: Error Ошибка %1 File not found. Check path and filename. %1 Файл не найден. Проверьте правильность пути и имени файла. All Files (*.*) Все файлы (*.*) Open Открыть Select a Directory Выбрать каталог Q3Ftp Not connected Нет соединения Host %1 not found Узел %1 не обнаружен Connection refused to host %1 Отказано в соединении с узлом %1 Connected to host %1 Установлено соединение с узлом %1 Connection refused for data connection Отказано в соединении передачи данных Unknown error Неизвестная ошибка Connecting to host failed: %1 Ошибка соединения с узлом: %1 Login failed: %1 Ошибка входа в систему: %1 Listing directory failed: %1 Ошибка просмотра каталога: %1 Changing directory failed: %1 Ошибка смены каталога: %1 Downloading file failed: %1 Ошибка загрузки файла: %1 Uploading file failed: %1 Ошибка отправки файла: %1 Removing file failed: %1 Ошибка удаления файла: %1 Creating directory failed: %1 Ошибка создания каталога: %1 Removing directory failed: %1 Ошибка удаления каталога: %1 Connection closed Соединение разорвано Host %1 found Обнаружен узел %1 Connection to %1 closed Соединение с узлом %1 разорвано Host found Узел обнаружен Connected to host Соединение с узлом установлено Q3Http Unknown error Неизвестная ошибка Request aborted Запрос отменен No server set to connect to Не выбран сервер для подключения Wrong content length Неверная длина данных Server closed connection unexpectedly Неожиданный разрыв соединения сервером Connection refused Отказано в соединении Host %1 not found Узел %1 не обнаружен HTTP request failed Ошибка HTTP-запроса Invalid HTTP response header Получен некорректный HTTP-заголовок Invalid HTTP chunked body Некорректный HTTP-ответ Host %1 found Обнаружен узел %1 Connected to host %1 Установлено соединение с узлом %1 Connection to %1 closed Соединение с узлом %1 разорвано Host found Узел обнаружен Connected to host Соединение с узлом установлено Connection closed Соединение разорвано Q3LocalFs Could not read directory %1 Невозможно просмотреть каталог %1 Could not create directory %1 Невозможно создать каталог %1 Could not remove file or directory %1 Невозможно удалить файл или каталог %1 Could not rename %1 to %2 Невозможно переименовать %1 в %2 Could not open %1 Невозможно открыть %1 Could not write %1 Невозможно записать %1 Q3MainWindow Line up Выровнять Customize... Настроить... Q3NetworkProtocol Operation stopped by the user Операция прервана пользователем Q3ProgressDialog Cancel Отмена Q3TabDialog OK OK Apply Применить Help Справка Defaults По умолчанию Cancel Отмена Q3TextEdit &Undo &Отменить &Redo &Повторить Cu&t &Вырезать &Copy &Копировать &Paste &Вставить Clear Очистить Select All Выделить все Q3ToolBar More... Больше... Q3UrlOperator The protocol `%1' is not supported Протокол `%1' не поддерживается The protocol `%1' does not support listing directories Протокол `%1' не поддерживает просмотр каталогов The protocol `%1' does not support creating new directories Протокол `%1' не поддерживает создание новых каталогов The protocol `%1' does not support removing files or directories Протокол `%1' не поддерживает удаление файлов или каталогов The protocol `%1' does not support renaming files or directories Протокол `%1' не поддерживает переименование файлов или каталогов The protocol `%1' does not support getting files Протокол `%1' не поддерживает доставку файлов The protocol `%1' does not support putting files Протокол `%1' не поддерживает отправку файлов The protocol `%1' does not support copying or moving files or directories Протокол `%1' не поддерживает копирование или перемещение файлов и каталогов (unknown) (неизвестно) Q3Wizard &Cancel &Отмена < &Back < &Назад &Next > &Вперед > &Finish &Финиш &Help &Справка QAbstractSocket Host not found Connection refused Отказано в соединении Socket operation timed out QAbstractSpinBox &Step up Step &down QAccel Space Space Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Print SysReq SysReq Home Home End End Left Left Up Up Right Right Down Down PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Ctrl Ctrl Alt Alt Shift Shift + + F%1 F%1 Menu Меню Help Справка Back Назад Forward Вперед Stop Стоп Refresh Обновить Volume Down Тише Volume Mute Выключить звук Volume Up Громче Bass Boost Bass Boost Bass Up Bass Up Bass Down Bass Down Treble Up Treble Up Treble Down Treble Down Media Play Воспроизведение Media Stop Остановить воспроизведение Media Previous Воспроизвести предыдущее Media Next Воспроизвести следующее Media Record Запись Favorites Избранное Search Поиск Standby Дежурный режим Open URL Открыть URL Launch Mail Почта Launch Media Проигрыватель Launch (0) Запустить (0) Launch (1) Запустить (1) Launch (2) Запустить (2) Launch (3) Запустить (3) Launch (4) Запустить (4) Launch (5) Запустить (5) Launch (6) Запустить (6) Launch (7) Запустить (7) Launch (8) Запустить (8) Launch (9) Запустить (9) Launch (A) Запустить (A) Launch (B) Запустить (B) Launch (C) Запустить (C) Launch (D) Запустить (D) Launch (E) Запустить (E) Launch (F) Запустить (F) Meta Meta QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. LTR Executable '%1' requires Qt %2, found Qt %3. Программный модуль '%1' требует Qt %2, найдена версия %3. Incompatible Qt Library Error Ошибка совместимости библиотеки Qt Activate Activates the program's main window QAquaStyle OK OK Cancel Отмена QAxServerBase &Help &Справка QColorDialog Hu&e: &Тон: &Sat: &Нас: &Val: &Ярк: &Red: &Крас: &Green: &Зел: Bl&ue: С&ин: A&lpha channel: &Альфа-канал: &Basic colors &Основные цвета &Custom colors &Собственные цвета &Define Custom Colors >> &Выбрать собственные цвета >> OK OK Cancel Отмена &Add to Custom Colors &Добавить к собственным цветам Select color Выбрать цвет QDataTable True True False False Insert Вставить Update Обновить Delete Удалить QDateTimeEdit AM am PM pm QDialog What's This? Что это? Help Справка QDialogButtons Yes to All OK to All No to All Cancel All Yes Да OK OK No Нет Cancel Отмена Apply Применить Ignore Retry Abort Help Справка %1 to All QDirModel Name Имя Size Размер Type Тип Modified QErrorMessage &Show this message again &Показывать это сообщение в дальнейшем &OK &OK Debug Message: Отладочное сообщение: Warning: Предупреждение: Fatal Error: Критическая ошибка: QFileDialog Copy or Move a File Копировать или переместить файл Read: %1 Открытие: %1 Write: %1 Запись: %1 Cancel Отмена All Files (*) Все файлы (*) Name Имя Size Размер Type Тип Date Дата Attributes Атрибуты OK OK Look &in: &Смотреть в: File &name: &Имя файла: File &type: &Тип файла: Back Назад One directory up Вверх на один уровень Create New Folder Создать новый каталог List View Список Detail View Детальный вид Preview File Info Предпросмотр информации о файле Preview File Contents Предпросмотр содержимого файла Read-write Чтение-запись Read-only Только чтение Write-only Только запись Inaccessible Нет доступа Symlink to File Ссылка на файл Symlink to Directory Ссылка на каталог Symlink to Special Ссылка на спецфайл File Файл Dir Каталог Special Спецфайл Open Открыть Save As Сохранить как &Open &Открыть &Save &Сохранить &Rename &Переименовать &Delete &Удалить R&eload О&бновить Sort by &Name По &имени Sort by &Size По &размеру Sort by &Date По &дате &Unsorted &Не упорядочивать Sort Упорядочить Show &hidden files Показать &скрытые файлы the file файл the directory каталог the symlink ссылку Delete %1 Удалить %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Вы действительно хотите удалить %1 "%2"?</qt> &Yes &Да &No &Нет New Folder 1 Новый каталог 1 New Folder Новый каталог New Folder %1 Новый каталог %1 Find Directory Найти каталог Directories Каталоги Save Сохранить Error Ошибка %1 File not found. Check path and filename. %1 Файл не найден. Проверьте правильность пути и имени файла. All Files (*.*) Все файлы (*.*) Open Открыть Select a Directory Выбрать каталог Directory: Каталог: %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer &Reload Parent Directory Look in: File name: Files of type: QFileDialogPrivate Sort Упорядочить &Open &Открыть &Rename &Переименовать &Delete &Удалить Sort by &Name По &имени Sort by &Size По &размеру Sort by &Date По &дате &Unsorted &Не упорядочивать Show &hidden files Показать &скрытые файлы Back Назад Create New Folder Создать новый каталог List View Список Detail View Детальный вид Open Открыть Cancel Отмена %1 Directory not found. Please verify the correct directory name was given. QFont Latin Латинский Greek Греческий Cyrillic Кириллица Armenian Армянский Georgian Грузинский Runic Рунический Ogham Огам Hebrew Иврит Arabic Арабский Syriac Сирийский Thaana Thaana Devanagari Деванагари Bengali Бенгальский Gurmukhi Gurmukhi Gujarati Gujarati Oriya Ория Tamil Тамильский Telugu Телугу Kannada Каннада Malayalam Малайялам Sinhala Sinhala Thai Тайский Lao Лаосский Tibetan Тибетский Myanmar Myanmar Khmer Кхмерский Han Han Hiragana Hiragana Katakana Katakana Hangul Хангул Bopomofo Bopomofo Yi Yi Ethiopic Эфиопский Cherokee Ирокезский Canadian Aboriginal Канадский аборигенный Mongolian Монгольский Currency Symbols Валютные символы Letterlike Symbols Буквенные символы Number Forms Числовые знаки Mathematical Operators Математические операторы Technical Symbols Технические символы Geometric Symbols Геометрические символы Miscellaneous Symbols Разнообразные символы Enclosed and Square Вложенные символы Braille Символы Брайля Unicode Уникод QFontDialog &Font &Шрифт Font st&yle &Стиль шрифта &Size &Размер Effects Эффекты Stri&keout &Перечеркивать &Underline П&одчеркивать &Color &Цвет Sample Пример Scr&ipt &Набор OK OK Apply Применить Cancel Отмена Close Закрыть Select Font Выбрать шрифт Wr&iting System QFtp Host %1 found Обнаружен узел %1 Host found Узел обнаружен Connected to host %1 Установлено соединение с узлом %1 Connected to host Соединение с узлом установлено Connection to %1 closed Соединение с узлом %1 разорвано Connection closed Соединение разорвано Host %1 not found Узел %1 не обнаружен Connection refused to host %1 Отказано в соединении с узлом %1 Unknown error Неизвестная ошибка Connecting to host failed: %1 Ошибка соединения с узлом: %1 Login failed: %1 Ошибка входа в систему: %1 Listing directory failed: %1 Ошибка просмотра каталога: %1 Changing directory failed: %1 Ошибка смены каталога: %1 Downloading file failed: %1 Ошибка загрузки файла: %1 Uploading file failed: %1 Ошибка отправки файла: %1 Removing file failed: %1 Ошибка удаления файла: %1 Creating directory failed: %1 Ошибка создания каталога: %1 Removing directory failed: %1 Ошибка удаления каталога: %1 Not connected Нет соединения Connection refused for data connection Отказано в соединении передачи данных QHeader %1 %1 QHostInfo Unknown error Неизвестная ошибка QHostInfoAgent Host not found Unknown address type Unknown error Неизвестная ошибка QHttp Connection refused Отказано в соединении Host %1 not found Узел %1 не обнаружен Wrong content length Неверная длина данных HTTP request failed Ошибка HTTP-запроса Host %1 found Обнаружен узел %1 Host found Узел обнаружен Connected to host %1 Установлено соединение с узлом %1 Connected to host Соединение с узлом установлено Connection to %1 closed Соединение с узлом %1 разорвано Connection closed Соединение разорвано Unknown error Неизвестная ошибка Request aborted Запрос отменен No server set to connect to Не выбран сервер для подключения Server closed connection unexpectedly Неожиданный разрыв соединения сервером Invalid HTTP response header Получен некорректный HTTP-заголовок Invalid HTTP chunked body Некорректный HTTP-ответ QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error Неизвестная ошибка QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK OK Cancel Отмена QLineEdit &Undo &Отменить &Redo &Повторить Cu&t &Вырезать &Copy &Копировать &Paste В&ставить Clear Очистить Select All Выделить все Delete Удалить QLineEditPrivate &Undo &Отменить &Redo &Повторить Cu&t &Вырезать &Copy &Копировать Delete Удалить Select All Выделить все QLocalFs Could not rename %1 to %2 Невозможно переименовать %1 в %2 Could not open %1 Невозможно открыть %1 Could not write %1 Невозможно записать %1 Could not read directory %1 Невозможно просмотреть каталог %1 Could not create directory %1 Невозможно создать каталог %1 Could not remove file or directory %1 Невозможно удалить файл или каталог %1 QMainWindow Line up Выровнять Customize... Настроить... QMenuBar About О программе Config Конфигурация Preference Настройки Options Параметры Setting Настройки Setup Настройки Quit Выход Exit Выход QMessageBox OK OK Cancel Отмена &Yes &Да &No &Нет &Abort &Прервать &Retry П&овторить &Ignore &Игнорировать <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for multiplatform GUI &amp; application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>О Qt</h3><p>Эта программа использует Qt версии %1.</p><p>Qt - это C++ GUI инструментарий для разработки многоплатформенных приложений.</p><p>Qt обеспечивает переносимость на уровне исходного кода между MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux и всеми основными версиями Unix.<br>Qt также доступен для встраиваемых систем.</p><p>Qt является продуктом Trolltech. См. <tt>http://www.trolltech.com/qt/</tt> для получения более подробной информации.</p> Yes to &All N&o to All About Qt Help Справка <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused Отказано в соединении The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QNetworkProtocol Operation stopped by the user Операция прервана пользователем QObject All Files (*) Все файлы (*) All Files (*.*) Все файлы (*.*) Open Открыть Save As Сохранить как Open Открыть Select a Directory Выбрать каталог Drive File Файл Directory Symbolic Link Unknown False False True True QPageSetupDialog OK OK Cancel Отмена Portrait Портрет Landscape Альбом QPrintDialog locally connected локальный Aliases: %1 Алиасы: %1 unknown неизвестно Unknown Location неизвестно OK OK Cancel Отмена Printer settings Настройки печати Print in color if available Цветная печать Print in grayscale В оттенках серого Print destination Направление печати Print to printer: Печать на принтер: Printer Принтер Host Узел Comment Комментарий Print to file: Печать в файл: Browse... Обзор... Options Параметры Print all Печатать все Print range Печатать диапазон From page: Со страницы: To page: До страницы: Print first page first Начать с первой страницы Print last page first Начать с последней страницы Number of copies: Число копий: Paper format Формат бумаги Portrait Портрет Landscape Альбом A0 (841 x 1189 mm) A0 (841 x 1189 мм) A1 (594 x 841 mm) A1 (594 x 841 мм) A2 (420 x 594 mm) A2 (420 x 594 мм) A3 (297 x 420 mm) A3 (297 x 420 мм) A4 (210x297 mm, 8.26x11.7 inches) A4 (210x297 мм, 8.26x11.7 дюйм) A5 (148 x 210 mm) A5 (148 x 210 мм) A6 (105 x 148 mm) A6 (105 x 148 мм) A7 (74 x 105 mm) A7 (74 x 105 мм) A8 (52 x 74 mm) A8 (52 x 74 мм) A9 (37 x 52 mm) A9 (37 x 52 мм) B0 (1000 x 1414 mm) B0 (1000 x 1414 мм) B1 (707 x 1000 mm) B1 (707 x 1000 мм) B2 (500 x 707 mm) B2 (500 x 707 мм) B3 (353 x 500 mm) B3 (353 x 500 мм) B4 (250 x 353 mm) B4 (250 x 353 мм) B5 (176 x 250 mm, 6.93x9.84 inches) B5 (176x250 мм, 6.93x9.84 дюйм) B6 (125 x 176 mm) B6 (125 x 176 мм) B7 (88 x 125 mm) B7 (88 x 125 мм) B8 (62 x 88 mm) B8 (62 x 88 мм) B9 (44 x 62 mm) B9 (44 x 62 мм) B10 (31 x 44 mm) B10 (31 x 44 мм) C5E (163 x 229 mm) C5E (163 x 229 мм) DLE (110 x 220 mm) DLE (110 x 220 мм) Executive (7.5x10 inches, 191x254 mm) Executive (7.5x10 дюйм, 191x254 мм) Folio (210 x 330 mm) Folio (210 x 330 мм) Ledger (432 x 279 mm) Ledger (432 x 279 мм) Legal (8.5x14 inches, 216x356 mm) Legal (8.5x14 дюйм, 216x356 мм) Letter (8.5x11 inches, 216x279 mm) Letter (8.5x11 дюйм, 216x279 мм) Tabloid (279 x 432 mm) Tabloid (279 x 432 мм) US Common #10 Envelope (105 x 241 mm) Конверт US #10 (105x241 мм) Setup Printer Настройки принтера PostScript Files (*.ps);;All Files (*) Файлы PostScript (*.ps);;Все файлы (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) B5 (176 x 250 mm, 6.93 x 9.84 inches) Executive (7.5 x 10 inches, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Print selection Page size: Orientation: Paper source: QPrintDialogPrivate Printer settings Настройки печати Print in color if available Цветная печать Print in grayscale В оттенках серого Print destination Направление печати Print to printer: Печать на принтер: Print to file: Печать в файл: Browse... Обзор... Options Параметры Print all Печатать все Print range Печатать диапазон From page: Со страницы: To page: До страницы: Print first page first Начать с первой страницы Print last page first Начать с последней страницы Number of copies: Число копий: Paper format Формат бумаги Portrait Портрет Landscape Альбом PostScript Files (*.ps);;All Files (*) Файлы PostScript (*.ps);;Все файлы (*) OK OK Cancel Отмена QProcess Unknown error Неизвестная ошибка QProgressBar %1% QProgressDialog Cancel Отмена QRegExp no error occurred ошибки отсутствуют disabled feature used использовались отключенные возможности bad char class syntax bad char class syntax bad lookahead syntax bad lookahead syntax bad repetition syntax bad repetition syntax invalid octal value некорректное восьмеричное значение missing left delim отсутствует левый разделитель unexpected end неожиданный конец met internal limit достигнуто внутреннее ограничение QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space Space Esc Esc Tab Tab Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Print SysReq SysReq Home Home End End Left Left Up Up Right Right Down Down PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Menu Меню Help Справка Back Назад Forward Вперед Stop Стоп Refresh Обновить Volume Down Тише Volume Mute Выключить звук Volume Up Громче Bass Boost Bass Boost Bass Up Bass Up Bass Down Bass Down Treble Up Treble Up Treble Down Treble Down Media Play Воспроизведение Media Stop Остановить воспроизведение Media Previous Воспроизвести предыдущее Media Next Воспроизвести следующее Media Record Запись Favorites Избранное Search Поиск Standby Дежурный режим Open URL Открыть URL Launch Mail Почта Launch Media Проигрыватель Launch (0) Запустить (0) Launch (1) Запустить (1) Launch (2) Запустить (2) Launch (3) Запустить (3) Launch (4) Запустить (4) Launch (5) Запустить (5) Launch (6) Запустить (6) Launch (7) Запустить (7) Launch (8) Запустить (8) Launch (9) Запустить (9) Launch (A) Запустить (A) Launch (B) Запустить (B) Launch (C) Запустить (C) Launch (D) Запустить (D) Launch (E) Запустить (E) Launch (F) Запустить (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert Вставить Delete Удалить Escape System Request Select Yes Да No Нет Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl Ctrl Shift Shift Alt Alt Meta Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete Удалить Delete this record? Удалить эту запись? Yes Да No Нет Insert Вставить Update Обновить Save edits? Сохранить изменения? Cancel Отмена Confirm Подтвердить Cancel your edits? Отменить изменения? QTabDialog OK OK Apply Применить Help Справка Defaults По умолчанию Cancel Отмена QTcpServer Socket operation unsupported QTextEdit &Undo &Отменить &Redo &Повторить Cu&t &Вырезать &Copy &Копировать &Paste &Вставить Clear Очистить Select All Выделить все Delete Удалить QTitleBar System Menu Системное меню Shade Свернуть в заголовок Unshade Восстановить из заголовка Normalize Восстановить Minimize Свернуть Maximize Развернуть Close Закрыть QToolBar More... Больше... QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QUrlOperator The protocol `%1' is not supported Протокол `%1' не поддерживается The protocol `%1' does not support listing directories Протокол `%1' не поддерживает просмотр каталогов The protocol `%1' does not support creating new directories Протокол `%1' не поддерживает создание новых каталогов The protocol `%1' does not support removing files or directories Протокол `%1' не поддерживает удаление файлов или каталогов The protocol `%1' does not support renaming files or directories Протокол `%1' не поддерживает переименование файлов или каталогов The protocol `%1' does not support getting files Протокол `%1' не поддерживает доставку файлов The protocol `%1' does not support putting files Протокол `%1' не поддерживает отправку файлов The protocol `%1' does not support copying or moving files or directories Протокол `%1' не поддерживает копирование или перемещение файлов и каталогов (unknown) (неизвестно) QWSDecoration &Restore &Восстановить &Move &Переместить &Size &Размер Mi&nimize &Свернуть Ma&ximize Р&азвернуть Close Закрыть Windows Windows KDE KDE KDE2 KDE2 BeOS BeOS Hydro Hydro Default По умолчанию QWhatsThisAction What's This? Что это? QWhatsThisButton What's this? Что это? QWidget * QWizard &Cancel &Отмена < &Back < &Назад &Next > &Вперед > &Finish &Финиш &Help &Справка QWorkspace &Restore &Восстановить &Move &Переместить &Size &Размер Mi&nimize &Свернуть Ma&ximize Р&азвернуть &Close &Закрыть Stay on &Top Всегда &наверху Sh&ade Свернуть в за&головок %1 - [%2] %1 - [%2] Minimize Свернуть Restore Down Восстановить Close Закрыть &Unshade Восстановить из за&головка QWorkspacePrivate &Restore &Восстановить &Move &Переместить &Size &Размер Mi&nimize &Свернуть Ma&ximize Р&азвернуть &Close &Закрыть Stay on &Top Всегда &наверху Sh&ade Свернуть в за&головок %1 - [%2] %1 - [%2] Minimize Свернуть Restore Down Восстановить Close Закрыть &Unshade Восстановить из за&головка QXml no error occurred ошибки отсутствуют error triggered by consumer ошибка инициирована пользователем unexpected end of file неожиданный конец файла more than one document type definition определен более, чем один тип документов error occurred while parsing element в процессе грамматического разбора элемента произошла ошибка tag mismatch отсутствует тег error occurred while parsing content в процессе грамматического разбора произошла ошибка unexpected character неожиданный символ invalid name for processing instruction некорректное имя директивы version expected while reading the XML declaration при чтении XML-тега ожидался параметр version wrong value for standalone declaration некорректное значение параметра standalone encoding declaration or standalone declaration expected while reading the XML declaration при чтении XML-тега ожидался параметр encoding или параметр standalone standalone declaration expected while reading the XML declaration при чтении XML-тега ожидался параметр standalone error occurred while parsing document type definition в процессе грамматического разбора типа документа произошла ошибка letter is expected ожидался символ error occurred while parsing comment в процессе грамматического разбора комментария произошла ошибка error occurred while parsing reference в процессе грамматического разбора ссылки произошла ошибка internal general entity reference not allowed in DTD internal general entity reference not allowed in DTD external parsed general entity reference not allowed in attribute value external parsed general entity reference not allowed in attribute value external parsed general entity reference not allowed in DTD external parsed general entity reference not allowed in DTD unparsed entity reference in wrong context unparsed entity reference in wrong context recursive entities рекурсивные объекты error in the text declaration of an external entity error in the text declaration of an external entity QtMultiLineEdit Undo Отменить Redo Повторить Cut Вырезать Copy Копировать Paste Вставить Paste special... Специальная вставка... Clear Очистить Select All Выделить все Transport Auth error mm3d-master/i18n/qt_sk.ts000066400000000000000000003651301324021725400154670ustar00rootroot00000000000000 Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True Pravda False Nepravda Insert Vložiť Update Delete Odstrániť Q3FileDialog Copy or Move a File Kopírovať alebo presunúť súbor Read: %1 Čítanie: %1 Write: %1 Zápis: %1 Cancel Zrušiť All Files (*) Všetky súbory (*) Name Názov Size Veľkosť Type Typ Date Dátum Attributes Atribúty &OK &OK Look &in: Hľadať &v: File &name: &Meno súboru: File &type: &Typ súboru: Back Dozadu One directory up O úroveň vyššie Create New Folder Vytvoriť nový priečinok List View Zoznam Detail View Detaily Preview File Info Informácie z náhľadu súboru Preview File Contents Náhľad obsahu súboru Read-write Čítanie a zápis Read-only Len na čítanie Write-only Len pre zápis Inaccessible Neprístupné Symlink to File Symbolický odkaz na súbor Symlink to Directory Symbolický odkaz na priečinok Symlink to Special Symbolický odkaz na špeciálny súbor File Súbor Dir Priečinok Special Špeciálny Open Otvoriť Save As Uložiť ako &Open &Otvoriť &Save &Uložiť &Rename Pre&menovať &Delete O&dstrániť R&eload O&bnoviť Sort by &Name Utriediť podľa &mena Sort by &Size Utriediť podľa &veľkosti Sort by &Date Utriediť podľa &dátumu &Unsorted &Netriediť Sort Triedenie Show &hidden files Zobraziť &skryté súbory the file súbor the directory priečinok the symlink symbolický odkaz Delete %1 Odstrániť %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Naozaj chcete odstrániť %1 "%2"?</qt> &Yes Án&o &No &Nie New Folder 1 Nový priečinok 1 New Folder Nový priečinok New Folder %1 Nový priečinok %1 Find Directory Nájsť priečinok Directories Priečinky Directory: Priečinok: Error Chyba %1 File not found. Check path and filename. %1 Súbor nenájdený. Overte cestu a meno súboru. All Files (*.*) Všetky súbory (*.*) Open Otvoriť Select a Directory Vyberte priečinok Q3Ftp Not connected Nepripojený Host %1 not found Hostiteľ %1 nenájdený Connection refused to host %1 Spojenie s hostiteľom %1 odmietnuté Connected to host %1 Pripojený k hostiteľovi %1 Connection refused for data connection Dátové spojenie odmietnuté Unknown error Neznáma chyba Connecting to host failed: %1 Spojenie s hostiteľom zlyhalo: %1 Login failed: %1 Prihlásenie zlyhalo: %1 Listing directory failed: %1 Výpis priečinku zlyhal: %1 Changing directory failed: %1 Zmena priečinku zlyhala: %1 Downloading file failed: %1 Stiahnutie súboru zlyhalo: %1 Uploading file failed: %1 Poslanie súboru zlyhalo: %1 Removing file failed: %1 Odstránenie súboru zlyhalo: %1 Creating directory failed: %1 Vytvorenie priečinku zlyhalo: %1 Removing directory failed: %1 Odstránenie priečinku zlyhalo: %1 Connection closed Spojenie ukončené Host %1 found Hostiteľ %1 nenájdený Connection to %1 closed Spojenie s %1 ukončené Host found Hostiteľ nájdený Connected to host Pripojený k hostiteľovi Q3Http Unknown error Neznáma chyba Request aborted Požiadavka zrušená No server set to connect to Nenastavený server na pripojenie Wrong content length Neplatná dĺžka obsahu Server closed connection unexpectedly Server neočakávane ukončil spojenie Connection refused Spojenie odmietnuté Host %1 not found Hostiteľ %1 nenájdený HTTP request failed Požiadavka HTTP zlyhala Invalid HTTP response header Neplatná hlavička odpovede HTTP Invalid HTTP chunked body Neplatné časti tela HTTP Host %1 found Hostiteľ %1 nenájdený Connected to host %1 Pripojený k hostiteľovi %1 Connection to %1 closed Spojenie s %1 ukončené Host found Hostiteľ nájdený Connected to host Pripojený k hostiteľovi Connection closed Spojenie ukončené Q3LocalFs Could not read directory %1 Nie je možné prečítať priečinok %1 Could not create directory %1 Nie je možné vytvoriť priečinok %1 Could not remove file or directory %1 Nie je možné odstrániť súbor alebo priečinok %1 Could not rename %1 to %2 Nie je možné premenovať %1 na %2 Could not open %1 Nie je možné otvoriť %1 Could not write %1 Nie je možné zapísať %1 Q3MainWindow Line up Vyrovnať Customize... Prispôsobiť... Q3NetworkProtocol Operation stopped by the user Operácia zastavená používateľom Q3ProgressDialog Cancel Zrušiť Q3TabDialog OK OK Apply Použiť Help Pomocník Defaults Štandardné Cancel Zrušiť Q3TextEdit &Undo V&rátiť späť &Redo &Opakovať vrátené Cu&t Vys&trihnúť &Copy &Kopírovať &Paste V&ložiť Clear Vyčistiť Select All Vybrať všetko Q3ToolBar More... Ďalšie... Q3UrlOperator The protocol `%1' is not supported Protokol %1 nie je podporovaný The protocol `%1' does not support listing directories Protokol %1 nepodporuje výpis priečinkov The protocol `%1' does not support creating new directories Protokol %1 nepodporuje vytváranie nových priečinkov The protocol `%1' does not support removing files or directories Protokol %1 nepodporuje odstránenie súborov a priečinkov The protocol `%1' does not support renaming files or directories Protokol %1 nepodporuje premenovanie súborov a priečinkov The protocol `%1' does not support getting files Protokol %1 nepodporuje získavanie súborov The protocol `%1' does not support putting files Protokol %1 nepodporuje ukladanie súborov The protocol `%1' does not support copying or moving files or directories Protokol %1 nepodporuje kopírovanie alebo presun súborov a priečinkov (unknown) (neznáma) Q3Wizard &Cancel &Zrušiť < &Back < &Dozadu &Next > Do&predu > &Finish &Dokončiť &Help &Pomocník QAbstractSocket Host not found Connection refused Spojenie odmietnuté Socket operation timed out QAbstractSpinBox &Step up Step &down QAccel Space Medzera Esc Esc Tab Tabulátor Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Print SysReq SysReq Home Home End End Left Vľavo Up Hore Right Vpravo Down Dolu PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Ctrl Ctrl Alt Alt Shift Shift + + F%1 F%1 Menu Menu Help Pomocník Back Dozadu Forward Dopredu Stop Stop Refresh Obnoviť Volume Down Znížiť hlasitosť Volume Mute Potichu Volume Up Zvýšiť hlasitosť Bass Boost Bass Boost Bass Up Zvýrazniť basové tóny Bass Down Potlačiť basové tóny Treble Up Zvýrazniť výsoké tóny Treble Down Potlačiť vysoké tóny Media Play Prehrávať Media Stop Zastaviť prehrávanie Media Previous Predchádzajúca Media Next Nasledujúca Media Record Nahrávať Favorites Obľúbené Search Nájsť Standby Standby Open URL Otvoriť URL Launch Mail Spustiť poštového klienta Launch Media Spustiť prehrávač Launch (0) Spustiť (0) Launch (1) Spustiť (1) Launch (2) Spustiť (2) Launch (3) Spustiť (3) Launch (4) Spustiť (4) Launch (5) Spustiť (5) Launch (6) Spustiť (6) Launch (7) Spustiť (7) Launch (8) Spustiť (8) Launch (9) Spustiť (9) Launch (A) Spustiť (A) Launch (B) Spustiť (B) Launch (C) Spustiť (C) Launch (D) Spustiť (D) Launch (E) Spustiť (E) Launch (F) Spustiť (F) Meta Meta QApplication QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. LTR Executable '%1' requires Qt %2, found Qt %3. Program '%1' vyžaduje Qt %2, nájdené Qt %3. Incompatible Qt Library Error Nekompatibilná knižnica Qt Activate Activates the program's main window QAquaStyle OK OK Cancel Zrušiť QAxServerBase &Help &Pomocník QColorDialog Hu&e: Od&tieň: &Sat: Na&s: &Val: &Hod: &Red: Če&rvená: &Green: &Zelená: Bl&ue: &Modrá: A&lpha channel: Kanál &alfa: &Basic colors &Základné farby &Custom colors &Vlastné farby &Define Custom Colors >> &Definovať vlastné farby >> OK OK Cancel Zrušiť &Add to Custom Colors Pridať k &vlastným farbám Select color Vybrať farbu QDataTable True Pravda False Nepravda Insert Vložiť Update Obnoviť Delete Odstrániť QDateTimeEdit AM am PM pm QDialog What's This? Čo je to? Help Pomocník QDialogButtons Yes to All OK to All No to All Cancel All Yes Áno OK OK No Nie Cancel Zrušiť Apply Použiť Ignore Retry Abort Help Pomocník %1 to All QDirModel Name Názov Size Veľkosť Type Typ Modified QErrorMessage &Show this message again &Zobraziť túto správu aj nabudúce &OK &OK Debug Message: Ladiaca správa: Warning: Varovanie: Fatal Error: Kritická chyba: QFileDialog Copy or Move a File Kopírovať alebo presunúť súbor Read: %1 Čítanie: %1 Write: %1 Zápis: %1 Cancel Zrušiť All Files (*) Všetky súbory (*) Name Názov Size Veľkosť Type Typ Date Dátum Attributes Atribúty OK OK Look &in: Hľadať &v: File &name: &Meno súboru: File &type: &Typ súboru: Back Dozadu One directory up O úroveň vyššie Create New Folder Vytvoriť nový priečinok List View Zoznam Detail View Detaily Preview File Info Informácie z náhľadu súboru Preview File Contents Náhľad obsahu súboru Read-write Čítanie a zápis Read-only Len na čítanie Write-only Len pre zápis Inaccessible Neprístupné Symlink to File Symbolický odkaz na súbor Symlink to Directory Symbolický odkaz na priečinok Symlink to Special Symbolický odkaz na špeciálny súbor File Súbor Dir Priečinok Special Špeciálny Open Otvoriť Save As Uložiť ako &Open &Otvoriť &Save &Uložiť &Rename Pre&menovať &Delete O&dstrániť R&eload O&bnoviť Sort by &Name Utriediť podľa &mena Sort by &Size Utriediť podľa &veľkosti Sort by &Date Utriediť podľa &dátumu &Unsorted &Netriediť Sort Triedenie Show &hidden files Zobraziť &skryté súbory the file súbor the directory priečinok the symlink symbolický odkaz Delete %1 Odstrániť %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>Naozaj chcete odstrániť %1 "%2"?</qt> &Yes Án&o &No &Nie New Folder 1 Nový priečinok 1 New Folder Nový priečinok New Folder %1 Nový priečinok %1 Find Directory Nájsť priečinok Directories Priečinky Save Uložiť Error Chyba %1 File not found. Check path and filename. %1 Súbor nenájdený. Overte cestu a meno súboru. All Files (*.*) Všetky súbory (*.*) Open Otvoriť Select a Directory Vyberte priečinok Directory: Priečinok: %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer &Reload Parent Directory Look in: File name: Files of type: QFileDialogPrivate Sort Triedenie &Open &Otvoriť &Rename Pre&menovať &Delete O&dstrániť Sort by &Name Utriediť podľa &mena Sort by &Size Utriediť podľa &veľkosti Sort by &Date Utriediť podľa &dátumu &Unsorted &Netriediť Show &hidden files Zobraziť &skryté súbory Back Dozadu Create New Folder Vytvoriť nový priečinok List View Zoznam Detail View Detaily Open Otvoriť Cancel Zrušiť %1 Directory not found. Please verify the correct directory name was given. QFont Latin Latinka Greek Grécke Cyrillic Azbuka Armenian Arménske Georgian Gruzínske Runic Runy Ogham Ogham Hebrew Hebrejské Arabic Arabské Syriac Sýrske Thaana Thaana Devanagari Devanagari Bengali Bengali Gurmukhi Gurmukhi Gujarati Gujarati Oriya Oriya Tamil Tamilské Telugu Telugu Kannada Kannada Malayalam Malayalam Sinhala Sinhala Thai Thajské Lao Laoské Tibetan Tibetské Myanmar Myanmar Khmer Khmérske Han Han Hiragana Hiragana Katakana Katakana Hangul Hangul Bopomofo Bopomofo Yi Yi Ethiopic Etiópske Cherokee Cherokee Canadian Aboriginal Kanadský pôvodní obyvatelia Mongolian Mongolské Currency Symbols Symboly mien Letterlike Symbols Symboly písmen Number Forms Číselné formáty Mathematical Operators Matematické operátory Technical Symbols Technické symboly Geometric Symbols Geometrické symboly Miscellaneous Symbols Rôzne symboly Enclosed and Square Zabalené Braille Braille Unicode Unicode QFontDialog &Font &Písmo Font st&yle Š&týl písma &Size &Veľkosť Effects Efekty Stri&keout Prečiar&knuť &Underline &Podčiarknuť &Color &Farba Sample Náhľad Scr&ipt Skr&ipt OK OK Apply Použiť Cancel Zrušiť Close Zavrieť Select Font Vybrať písmo Wr&iting System QFtp Host %1 found Hostiteľ %1 nenájdený Host found Hostiteľ nájdený Connected to host %1 Pripojený k hostiteľovi %1 Connected to host Pripojený k hostiteľovi Connection to %1 closed Spojenie s %1 ukončené Connection closed Spojenie ukončené Host %1 not found Hostiteľ %1 nenájdený Connection refused to host %1 Spojenie s hostiteľom %1 odmietnuté Unknown error Neznáma chyba Connecting to host failed: %1 Spojenie s hostiteľom zlyhalo: %1 Login failed: %1 Prihlásenie zlyhalo: %1 Listing directory failed: %1 Výpis priečinku zlyhal: %1 Changing directory failed: %1 Zmena priečinku zlyhala: %1 Downloading file failed: %1 Stiahnutie súboru zlyhalo: %1 Uploading file failed: %1 Poslanie súboru zlyhalo: %1 Removing file failed: %1 Odstránenie súboru zlyhalo: %1 Creating directory failed: %1 Vytvorenie priečinku zlyhalo: %1 Removing directory failed: %1 Odstránenie priečinku zlyhalo: %1 Not connected Nepripojený Connection refused for data connection Dátové spojenie odmietnuté QHeader %1 %1 QHostInfo Unknown error Neznáma chyba QHostInfoAgent Host not found Unknown address type Unknown error Neznáma chyba QHttp Connection refused Spojenie odmietnuté Host %1 not found Hostiteľ %1 nenájdený Wrong content length Neplatná dĺžka obsahu HTTP request failed Požiadavka HTTP zlyhala Host %1 found Hostiteľ %1 nenájdený Host found Hostiteľ nájdený Connected to host %1 Pripojený k hostiteľovi %1 Connected to host Pripojený k hostiteľovi Connection closed Spojenie ukončené Unknown error Neznáma chyba Request aborted Požiadavka zrušená No server set to connect to Nenastavený server na pripojenie Server closed connection unexpectedly Server neočakávane ukončil spojenie Invalid HTTP response header Neplatná hlavička odpovede HTTP Invalid HTTP chunked body Neplatné časti tela HTTP Connection to %1 closed Spojenie s %1 ukončené QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error Neznáma chyba QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK OK Cancel Zrušiť QLineEdit &Undo V&rátiť späť &Redo &Opakovať vrátené Cu&t Vys&trihnúť &Copy &Kopírovať &Paste V&ložiť Clear Vyčistiť Select All Vybrať všetko Delete Odstrániť QLineEditPrivate &Undo V&rátiť späť &Redo &Opakovať vrátené Cu&t Vys&trihnúť &Copy &Kopírovať &Paste V&ložiť Delete Odstrániť Select All Vybrať všetko QLocalFs Could not rename %1 to %2 Nie je možné premenovať %1 na %2 Could not open %1 Nie je možné otvoriť %1 Could not write %1 Nie je možné zapísať %1 Could not read directory %1 Nie je možné prečítať priečinok %1 Could not create directory %1 Nie je možné vytvoriť priečinok %1 Could not remove file or directory %1 Nie je možné odstrániť súbor alebo priečinok %1 QMainWindow Line up Vyrovnať Customize... Prispôsobiť... QMenuBar About O programe Config Konfigurácia Preference Nastavenie Options Možnosti Setting Nastavenie Setup Nastavenie Quit Koniec Exit Koniec QMessageBox OK OK Cancel Zrušiť &Yes Án&o &No &Nie &Abort &Prerušiť &Retry &Znovu &Ignore &Ignorovať <h3>About Qt</h3><p>This program uses Qt version %1.</p><p>Qt is a C++ toolkit for multiplatform GUI &amp; application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants.<br>Qt is also available for embedded devices.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>O Qt</h3> <p>Tento program používa Qt verzie %1.</p> <p>Qt je C++ knižnica pre multiplatformové GUI &amp; vývoj aplikácii.</p> <p>Poskytuje portabilitu jednotného kódu na MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, a mnohé ďalšie komerčné verzie Unixu. <br>Qt je dostupné aj pre malé zariadenia.</p> <p>Qt je produkt firmy Trolltech. Pre ďalšie informácie navštívte <tt>http://www.trolltech.com/qt/</tt>.</p> Yes to &All N&o to All About Qt Help Pomocník <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused Spojenie odmietnuté The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QNetworkProtocol Operation stopped by the user Operácia zastavená používateľom QObject All Files (*) Všetky súbory (*) All Files (*.*) Všetky súbory (*.*) Open Otvoriť Save As Uložiť ako Open Otvoriť Select a Directory Vyberte priečinok Drive File Súbor Directory Symbolic Link Unknown False Nepravda True Pravda QPageSetupDialog OK OK Cancel Zrušiť Portrait Na výšku Landscape Na šírku QPrintDialog locally connected lokálne pripojená Aliases: %1 Aliasy: %1 unknown neznámy Unknown Location Neznáme umiestnenie OK OK Cancel Zrušiť Printer settings Nastavenie tlačiarne Print in color if available Tlačiť farebne Print in grayscale Tlačiť v odtieňoch šedej Print destination Cieľ tlače Print to printer: Tlačiť na tlačiareň: Printer Tlačiareň Host Hostiteľ Comment Komentár Print to file: Tlačiť do súboru: Browse... Prechádzať... Options Možnosti Print all Tlačiť všetky Print range Rozsah tlače From page: Od stránky: To page: Do stránky: Print first page first Prvú stránku najprv Print last page first Poslednú stránku najprv Number of copies: Počet kópií: Paper format Formát papiera Portrait Na výšku Landscape Na šírku A0 (841 x 1189 mm) A0 (841 x 1189 mm) A1 (594 x 841 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A3 (297 x 420 mm) A4 (210x297 mm, 8.26x11.7 inches) A4 (210x297 mm, 8.26x11.7 palcov) A5 (148 x 210 mm) A5 (148 x 210 mm) A6 (105 x 148 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B4 (250 x 353 mm) B5 (176 x 250 mm, 6.93x9.84 inches) B5 (176 x 250 mm, 6.93x9.84 palcov) B6 (125 x 176 mm) B6 (125 x 176 mm) B7 (88 x 125 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) DLE (110 x 220 mm) Executive (7.5x10 inches, 191x254 mm) Executive (7.5x10 palcov, 191x254 mm) Folio (210 x 330 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Ledger (432 x 279 mm) Legal (8.5x14 inches, 216x356 mm) Legal (8.5x14 palcov, 216x356 mm) Letter (8.5x11 inches, 216x279 mm) Letter (8.5x11 palcov, 216x279 mm) Tabloid (279 x 432 mm) Tabloid (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) Obálka US Common #10 (105 x 241 mm) Setup Printer Nastaviť tlačiareň PostScript Files (*.ps);;All Files (*) Súbory PostScript (*.ps);;Všetky súbory (*) A4 (210 x 297 mm, 8.26 x 11.7 inches) B5 (176 x 250 mm, 6.93 x 9.84 inches) Executive (7.5 x 10 inches, 191 x 254 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Print selection Page size: Orientation: Paper source: QPrintDialogPrivate Printer settings Nastavenie tlačiarne Print in color if available Tlačiť farebne Print in grayscale Tlačiť v odtieňoch šedej Print destination Cieľ tlače Print to printer: Tlačiť na tlačiareň: Print to file: Tlačiť do súboru: Browse... Prechádzať... Options Možnosti Print all Tlačiť všetky Print range Rozsah tlače From page: Od stránky: To page: Do stránky: Print first page first Prvú stránku najprv Print last page first Poslednú stránku najprv Number of copies: Počet kópií: Paper format Formát papiera Portrait Na výšku Landscape Na šírku PostScript Files (*.ps);;All Files (*) Súbory PostScript (*.ps);;Všetky súbory (*) OK OK Cancel Zrušiť QProcess Unknown error Neznáma chyba QProgressBar %1% QProgressDialog Cancel Zrušiť QRegExp no error occurred žiadne chyby disabled feature used použitá vypnutá funkcia bad char class syntax neplatný zápis triedy znakov bad lookahead syntax neplatný zápis výhľadu bad repetition syntax neplatný zápis opakovania invalid octal value neplatná osmičková hodnota missing left delim chýbajúci pravý oddeľovač unexpected end neočakávaný koniec met internal limit dosiahnutý interný limit QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space Medzera Esc Esc Tab Tabulátor Backtab Backtab Backspace Backspace Return Return Enter Enter Ins Ins Del Del Pause Pause Print Print SysReq SysReq Home Home End End Left Vľavo Up Hore Right Vpravo Down Dolu PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Menu Menu Help Pomocník Back Dozadu Forward Dopredu Stop Stop Refresh Obnoviť Volume Down Znížiť hlasitosť Volume Mute Potichu Volume Up Zvýšiť hlasitosť Bass Boost Bass Boost Bass Up Zvýrazniť basové tóny Bass Down Potlačiť basové tóny Treble Up Zvýrazniť výsoké tóny Treble Down Potlačiť vysoké tóny Media Play Prehrávať Media Stop Zastaviť prehrávanie Media Previous Predchádzajúca Media Next Nasledujúca Media Record Nahrávať Favorites Obľúbené Search Nájsť Standby Standby Open URL Otvoriť URL Launch Mail Spustiť poštového klienta Launch Media Spustiť prehrávač Launch (0) Spustiť (0) Launch (1) Spustiť (1) Launch (2) Spustiť (2) Launch (3) Spustiť (3) Launch (4) Spustiť (4) Launch (5) Spustiť (5) Launch (6) Spustiť (6) Launch (7) Spustiť (7) Launch (8) Spustiť (8) Launch (9) Spustiť (9) Launch (A) Spustiť (A) Launch (B) Spustiť (B) Launch (C) Spustiť (C) Launch (D) Spustiť (D) Launch (E) Spustiť (E) Launch (F) Spustiť (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert Vložiť Delete Odstrániť Escape System Request Select Yes Áno No Nie Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl Ctrl Shift Shift Alt Alt Meta Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete Odstrániť Delete this record? Odstrániť tento záznam? Yes Áno No Nie Insert Vložiť Update Aktualizovať Save edits? Uložiť zmeny? Cancel Zrušiť Confirm Potvrdenie Cancel your edits? Zahodiť zmeny? QTabDialog OK OK Apply Použiť Help Pomocník Defaults Štandardné Cancel Zrušiť QTcpServer Socket operation unsupported QTextEdit &Undo V&rátiť späť &Redo &Opakovať vrátené Cu&t Vys&trihnúť &Copy &Kopírovať &Paste V&ložiť Clear Vyčistiť Select All Vybrať všetko Delete Odstrániť QTitleBar System Menu Systémové menu Shade Zabaliť Unshade Rozbaliť Normalize Normalizovať Minimize Minimalizovať Maximize Maximalizovať Close Zavrieť QToolBar More... Ďalšie... QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QUrlOperator The protocol `%1' is not supported Protokol %1 nie je podporovaný The protocol `%1' does not support listing directories Protokol %1 nepodporuje výpis priečinkov The protocol `%1' does not support creating new directories Protokol %1 nepodporuje vytváranie nových priečinkov The protocol `%1' does not support removing files or directories Protokol %1 nepodporuje odstránenie súborov a priečinkov The protocol `%1' does not support renaming files or directories Protokol %1 nepodporuje premenovanie súborov a priečinkov The protocol `%1' does not support getting files Protokol %1 nepodporuje získavanie súborov The protocol `%1' does not support putting files Protokol %1 nepodporuje ukladanie súborov The protocol `%1' does not support copying or moving files or directories Protokol %1 nepodporuje kopírovanie alebo presun súborov a priečinkov (unknown) (neznáma) QWSDecoration &Restore &Obnoviť &Move &Presunúť &Size &Veľkosť Mi&nimize Mi&nimalizovať Ma&ximize Ma&ximalizovať Close Zavrieť Windows Windows KDE KDE KDE2 KDE2 BeOS BeOS Hydro Hydro Default Štandard QWhatsThisAction What's This? Čo je to? QWhatsThisButton What's this? Čo je to? QWidget * QWizard &Cancel &Zrušiť < &Back < &Dozadu &Next > Do&predu > &Finish &Dokončiť &Help &Pomocník QWorkspace &Restore &Obnoviť &Move &Presunúť &Size &Veľkosť Mi&nimize Mi&nimalizovať Ma&ximize Ma&ximalizovať &Close &Zavrieť Stay on &Top Nechať navr&chu Sh&ade Za&baliť %1 - [%2] %1 - [%2] Minimize Minimalizovať Restore Down Obnoviť dolu Close Zavrieť &Unshade &Rozbaliť QWorkspacePrivate &Restore &Obnoviť &Move &Presunúť &Size &Veľkosť Mi&nimize Mi&nimalizovať Ma&ximize Ma&ximalizovať &Close &Zavrieť Stay on &Top Nechať navr&chu Sh&ade Za&baliť %1 - [%2] %1 - [%2] Minimize Minimalizovať Restore Down Obnoviť dolu Close Zavrieť &Unshade &Rozbaliť QXml no error occurred žiadna chyba error triggered by consumer chyba vyvolaná zákazníkom unexpected end of file neočakávaný koniec súboru more than one document type definition viac ako jedna definícia typu dokumentu error occurred while parsing element chyba počas spracovania elementu tag mismatch nezodpovedajúca značka error occurred while parsing content chyba počas spracovania obsahu unexpected character neočakávaný znak invalid name for processing instruction neplatné meno pre inštrukciu spracovania version expected while reading the XML declaration očakávaný verzia počas čítania deklarácie XML wrong value for standalone declaration neplatná hodnota pre samostatnú deklaráciu encoding declaration or standalone declaration expected while reading the XML declaration očakávané kódovanie deklarácie alebo samostatnej deklarácie počas čítania deklarácie XML standalone declaration expected while reading the XML declaration očakávaná samostatná deklarácia počas čítania deklarácie XML error occurred while parsing document type definition chyba počas spracovania definície typu dokumentu letter is expected očakáva sa písmeno error occurred while parsing comment chyba počas spracovania dokumentu error occurred while parsing reference chyba počas spracovania odkazu internal general entity reference not allowed in DTD interný všeobecný odkaz na entitu nie je možný v DTD external parsed general entity reference not allowed in attribute value externý spracovaný odkaz na všeobecnú entitu nie je možný v hodnote atribútu external parsed general entity reference not allowed in DTD externý spracovaný odkaz na všeobecnú entitu nie je možný v DTD unparsed entity reference in wrong context nespracovaný odkaz na entitu v neplatnom kontexte recursive entities rekurzívne entity error in the text declaration of an external entity chyba v deklarácii textu externej entity QtMultiLineEdit Undo Vrátiť späť Redo Opakovať vrátené Cut Vystrihnúť Copy Kopírovať Paste Vložiť Paste special... Vložiť inak... Clear Vyčistiť Select All Vybrať všetko Transport Auth error mm3d-master/i18n/qt_untranslated.ts000066400000000000000000002147161324021725400175610ustar00rootroot00000000000000 Q3Accel %1, %2 not defined Ambiguous %1 not handled Q3DataTable True False Insert Update Delete Q3FileDialog Copy or Move a File Read: %1 Write: %1 Cancel All Files (*) Name Size Type Date Attributes &OK Look &in: File &name: File &type: Back One directory up Create New Folder List View Detail View Preview File Info Preview File Contents Read-write Read-only Write-only Inaccessible Symlink to File Symlink to Directory Symlink to Special File Dir Special Open Save As &Open &Save &Rename &Delete R&eload Sort by &Name Sort by &Size Sort by &Date &Unsorted Sort Show &hidden files the file the directory the symlink Delete %1 <qt>Are you sure you wish to delete %1 "%2"?</qt> &Yes &No New Folder 1 New Folder New Folder %1 Find Directory Directories Directory: Error %1 File not found. Check path and filename. All Files (*.*) Open Select a Directory Q3LocalFs Could not read directory %1 Could not create directory %1 Could not remove file or directory %1 Could not rename %1 to %2 Could not open %1 Could not write %1 Q3MainWindow Line up Customize... Q3NetworkProtocol Operation stopped by the user Q3ProgressDialog Cancel Q3TabDialog OK Apply Help Defaults Cancel Q3TextEdit &Undo &Redo Cu&t &Copy &Paste Clear Select All Q3ToolBar More... Q3UrlOperator The protocol `%1' is not supported The protocol `%1' does not support listing directories The protocol `%1' does not support creating new directories The protocol `%1' does not support removing files or directories The protocol `%1' does not support renaming files or directories The protocol `%1' does not support getting files The protocol `%1' does not support putting files The protocol `%1' does not support copying or moving files or directories (unknown) Q3Wizard &Cancel < &Back &Next > &Finish &Help QAbstractSocket Host not found Connection refused Socket operation timed out QAbstractSpinBox &Step up Step &down QApplication Activate Executable '%1' requires Qt %2, found Qt %3. Incompatible Qt Library Error QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. Activates the program's main window QColorDialog Hu&e: &Sat: &Val: &Red: &Green: Bl&ue: A&lpha channel: &Basic colors &Custom colors &Define Custom Colors >> OK Cancel &Add to Custom Colors Select color QDateTimeEdit AM am PM pm QDialog What's This? QDialogButtons Yes to All OK to All No to All Cancel All Yes OK No Cancel Apply Ignore Retry Abort Help %1 to All QDirModel Name Size Type Modified QErrorMessage Debug Message: Warning: Fatal Error: &Show this message again &OK QFileDialog All Files (*) Directories &Open &Save Open Save %1 already exists. Do you want to replace it? %1 File not found. Please verify the correct file name was given. My Computer Sort &Rename &Delete &Reload Sort by &Name Sort by &Size Sort by &Date &Unsorted Show &hidden files Back Parent Directory Create New Folder List View Detail View Look in: File name: Files of type: Cancel QFileDialogPrivate %1 Directory not found. Please verify the correct directory name was given. QFontDialog &Font Font st&yle &Size Effects Stri&keout &Underline Sample Wr&iting System OK Apply Cancel Close Select Font QFtp Not connected Host %1 not found Connection refused to host %1 Connected to host %1 Connection refused for data connection Unknown error Connecting to host failed: %1 Login failed: %1 Listing directory failed: %1 Changing directory failed: %1 Downloading file failed: %1 Uploading file failed: %1 Removing file failed: %1 Creating directory failed: %1 Removing directory failed: %1 Connection closed Host %1 found Connection to %1 closed Host found Connected to host QHostInfo Unknown error QHostInfoAgent Host not found Unknown address type Unknown error QHttp Unknown error Request aborted No server set to connect to Wrong content length Server closed connection unexpectedly Connection refused Host %1 not found HTTP request failed Invalid HTTP response header Invalid HTTP chunked body Host %1 found Connected to host %1 Connection to %1 closed Host found Connected to host Connection closed QIODevice Permission denied Too many open files No such file or directory No space left on device Unknown error QInputContext XIM XIM input method Windows input method Mac OS X input method QInputDialog OK Cancel QLineEdit &Undo &Redo Cu&t &Copy &Paste Delete Select All QMessageBox Help OK Cancel &Yes &No &Abort &Retry &Ignore Yes to &All N&o to All <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> About Qt <p>This program uses Qt version %1.</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> QNativeSocketEngine The remote host closed the connection Network operation timed out Out of resources Unsupported socket operation Protocol type not supported Invalid socket descriptor Network unreachable Permission denied Connection timed out Connection refused The bound address is already in use The address is not available The address is protected Datagram was to large to send Unable to send a message Unable to receive a message Unable to write Network error Another socket is already listening on the same port Unable to initialize non-blocking socket Unable to initialize broadcast socket Attempt to use IPv6 socket on a platform with no IPv6 support QObject All Files (*) All Files (*.*) Open Save As Open Select a Directory Drive File Directory Symbolic Link Unknown False True QPrintDialog locally connected Aliases: %1 unknown Unknown Location Printer settings Print in color if available Print in grayscale Print destination Print to printer: Print to file: Browse... Options Print all Print selection Print range From page: To page: Print first page first Print last page first Number of copies: Paper format Portrait Landscape A0 (841 x 1189 mm) A1 (594 x 841 mm) A2 (420 x 594 mm) A3 (297 x 420 mm) A4 (210 x 297 mm, 8.26 x 11.7 inches) A5 (148 x 210 mm) A6 (105 x 148 mm) A7 (74 x 105 mm) A8 (52 x 74 mm) A9 (37 x 52 mm) B0 (1000 x 1414 mm) B1 (707 x 1000 mm) B2 (500 x 707 mm) B3 (353 x 500 mm) B4 (250 x 353 mm) B5 (176 x 250 mm, 6.93 x 9.84 inches) B6 (125 x 176 mm) B7 (88 x 125 mm) B8 (62 x 88 mm) B9 (44 x 62 mm) B10 (31 x 44 mm) C5E (163 x 229 mm) DLE (110 x 220 mm) Executive (7.5 x 10 inches, 191 x 254 mm) Folio (210 x 330 mm) Ledger (432 x 279 mm) Legal (8.5 x 14 inches, 216 x 356 mm) Letter (8.5 x 11 inches, 216 x 279 mm) Tabloid (279 x 432 mm) US Common #10 Envelope (105 x 241 mm) PostScript Files (*.ps);;All Files (*) OK Cancel Page size: Orientation: Paper source: QProcess Unknown error QProgressBar %1% QProgressDialog Cancel QRegExp no error occurred disabled feature used bad char class syntax bad lookahead syntax bad repetition syntax invalid octal value missing left delim unexpected end met internal limit QScrollBar Scroll here Left edge Top Right edge Bottom Page left Page up Page right Page down Scroll left Scroll up Scroll right Scroll down QShortcut Space Esc Tab Backtab Backspace Return Enter Ins Del Pause Print SysReq Home End Left Up Right Down PgUp PgDown CapsLock NumLock ScrollLock Menu Help Back Forward Stop Refresh Volume Down Volume Mute Volume Up Bass Boost Bass Up Bass Down Treble Up Treble Down Media Play Media Stop Media Previous Media Next Media Record Favorites Search Standby Open URL Launch Mail Launch Media Launch (0) Launch (1) Launch (2) Launch (3) Launch (4) Launch (5) Launch (6) Launch (7) Launch (8) Launch (9) Launch (A) Launch (B) Launch (C) Launch (D) Launch (E) Launch (F) Print Screen Page Up Page Down Caps Lock Num Lock Number Lock Scroll Lock Insert Delete Escape System Request Select Yes No Context1 Context2 Context3 Context4 Call Hangup Flip Ctrl Shift Alt Meta + F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server QSql Delete Delete this record? Yes No Insert Update Save edits? Cancel Confirm Cancel your edits? QTcpServer Socket operation unsupported QTextEdit &Undo &Redo Cu&t &Copy &Paste Delete Select All QUdpSocket This platform does not support IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark RLM Right-to-left mark ZWJ Zero width joiner ZWNJ Zero width non-joiner ZWSP Zero width space LRE Start of left-to-right embedding RLE Start of right-to-left embedding LRO Start of left-to-right override RLO Start of right-to-left override PDF Pop directional formatting Insert Unicode control character QWhatsThisAction What's This? QWidget * QWorkspace &Restore &Move &Size Mi&nimize Ma&ximize &Close Stay on &Top Sh&ade %1 - [%2] Minimize Restore Down Close &Unshade QXml no error occurred error triggered by consumer unexpected end of file more than one document type definition error occurred while parsing element tag mismatch error occurred while parsing content unexpected character invalid name for processing instruction version expected while reading the XML declaration wrong value for standalone declaration encoding declaration or standalone declaration expected while reading the XML declaration standalone declaration expected while reading the XML declaration error occurred while parsing document type definition letter is expected error occurred while parsing comment error occurred while parsing reference internal general entity reference not allowed in DTD external parsed general entity reference not allowed in attribute value external parsed general entity reference not allowed in DTD unparsed entity reference in wrong context recursive entities error in the text declaration of an external entity mm3d-master/i18n/qt_zh_CN.ts000066400000000000000000002155461324021725400160600ustar00rootroot00000000000000 Q3Accel %1, %2 not defined %1,%2未定义 Ambiguous %1 not handled 不明确的%1没有被处理 Q3DataTable True False Insert 插入 Update 更新 Delete 删除 Q3FileDialog Copy or Move a File 复制或者移动一个文件 Read: %1 读取:%1 Write: %1 写入:%1 Cancel 取消 All Files (*) 所有文件 (*) Name 名称 Size 大小 Type 类型 Date 日期 Attributes 属性 &OK 确定(&O) Look &in: 查找范围(&I): File &name: 文件名称(&N): File &type: 文件类型(&T): Back 后退 One directory up 向上一级 Create New Folder 创建新文件夹 List View 列表视图 Detail View 详细视图 Preview File Info 预览文件信息 Preview File Contents 预览文件内容 Read-write 读写 Read-only 只读 Write-only 只写 Inaccessible 不可访问的 Symlink to File 文件的系统链接 Symlink to Directory 目录的系统链接 Symlink to Special 特殊的系统链接 File 文件 Dir 目录 Special 特殊 Open 打开 Save As 另存为 &Open 打开(&O) &Save 保存(&S) &Rename 重命名(&R) &Delete 删除(&D) R&eload 重新载入(&E) Sort by &Name 按名称排列(&N) Sort by &Size 按大小排列(&S) Sort by &Date 按日期排列(&D) &Unsorted 未排列的(&U) Sort 排列 Show &hidden files 显示隐藏文件(&H) the file 文件 the directory 目录 the symlink 系统链接 Delete %1 删除%1 <qt>Are you sure you wish to delete %1 "%2"?</qt> <qt>你确认你想删除%1,“%2”?</qt> &Yes 是(&Y) &No 否(&N) New Folder 1 新建文件夹1 New Folder 新建文件夹 New Folder %1 新建文件夹%1 Find Directory 查找目录 Directories 目录 Directory: 目录: Error 错误 %1 File not found. Check path and filename. 文件%1 未找到。 请检查路径和文件名。 All Files (*.*) 所有文件 (*.*) Open 打开 Select a Directory 选择一个目录 Q3LocalFs Could not read directory %1 不能读取目录 %1 Could not create directory %1 不能创建目录 %1 Could not remove file or directory %1 不能移除文件或者目录 %1 Could not rename %1 to %2 不能把 %1 重命名为 %2 Could not open %1 不能打开 %1 Could not write %1 不能写入 %1 Q3MainWindow Line up 排列 Customize... 自定义... Q3NetworkProtocol Operation stopped by the user 操作被用户停止 Q3ProgressDialog Cancel 取消 Q3TabDialog OK 确认 Apply 应用 Help 帮助 Defaults 默认 Cancel 取消 Q3TextEdit &Undo 撤消(&U) &Redo 恢复(&R) Cu&t 剪切(&T) &Copy 复制(&C) &Paste 粘贴(&P) Clear 清空 Select All 选择全部 Q3ToolBar More... 更多... Q3UrlOperator The protocol `%1' is not supported 协议“%1”不被支持 The protocol `%1' does not support listing directories 协议“%1”不支持列出目录 The protocol `%1' does not support creating new directories 协议“%1”不支持创建新目录 The protocol `%1' does not support removing files or directories 协议“%1”不支持移除文件或者目录 The protocol `%1' does not support renaming files or directories 协议“%1”不支持重命名文件或者目录 The protocol `%1' does not support getting files 协议“%1”不支持获取文件 The protocol `%1' does not support putting files 协议“%1”不支持上传文件 The protocol `%1' does not support copying or moving files or directories 协议“%1”不支持复制或者移动文件或者目录 (unknown) (未知的) Q3Wizard &Cancel 取消(&C) < &Back < 上一步(&B) &Next > 下一步(&N) > &Finish 完成(&F) &Help 帮助(&H) QAbstractSocket Host not found 主机未找到 Connection refused 连接被拒绝 Socket operation timed out 套接字操作超时 QAbstractSpinBox &Step up 增加(&S) Step &down 减少(&D) QApplication Activate 激活 Executable '%1' requires Qt %2, found Qt %3. 执行“%1”需要Qt %2,只找到了Qt %3。 Incompatible Qt Library Error 不兼容的Qt错误 QT_LAYOUT_DIRECTION Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. LTR Activates the program's main window 激活这个程序的主窗口 QColorDialog Hu&e: 色调(&E): &Sat: 饱和度(&S): &Val: 亮度(&V): &Red: 红色(&R): &Green: 绿色(&G): Bl&ue: 蓝色(&U): A&lpha channel: Alpha通道(&A): &Basic colors 基本颜色(&B) &Custom colors 自定义颜色(&C) &Define Custom Colors >> 定义自定义颜色(&D) >> OK 确定 Cancel 取消 &Add to Custom Colors 添加到自定义颜色(&A) Select color 选择颜色 QDateTimeEdit AM am PM pm QDialog What's This? 这是什么? QDialogButtons Yes to All 全部是 OK to All 全部确定 No to All 全部否 Cancel All 取消全部 Yes OK 确定 No Cancel 取消 Apply 应用 Ignore 忽略 Retry 重试 Abort 放弃 Help 帮助 %1 to All 全部%1 QDirModel Name 名称 Size 大小 Type 类型 Modified 修改 QErrorMessage Debug Message: 调试消息: Warning: 警告: Fatal Error: 致命错误: &Show this message again 再次显示这个消息(&S) &OK 确定(&O) QFileDialog All Files (*) 所有文件 (*) Directories 目录 &Open 打开(&O) &Save 保存(&S) Open 打开 Save 保存 %1 already exists. Do you want to replace it? %1已经存在。你想要替换它么? %1 File not found. Please verify the correct file name was given. 文件%1 没有找到。 请核实已给定正确文件名。 My Computer 我的计算机 Sort 排列 &Rename 重命名(&R) &Delete 删除(&D) &Reload 重新载入(&R) Sort by &Name 按名称排列(&N) Sort by &Size 按大小排列(&S) Sort by &Date 按日期排列(&D) &Unsorted 未排列的(&U) Show &hidden files 显示隐藏文件(&H) Back 后退 Parent Directory 父目录 Create New Folder 创建新文件夹 List View 列表视图 Detail View 详细视图 Look in: 查找: File name: 文件名: Files of type: 文件类型: Cancel 取消 QFileDialogPrivate %1 Directory not found. Please verify the correct directory name was given. 目录%1 没有找到。 请核实已给定正确目录名。 QFontDialog &Font 字体(&F) Font st&yle 字体风格(&Y) &Size 大小(&S) Effects 效果 Stri&keout 删除线(&K) &Underline 下划线(&U) Sample 实例 Wr&iting System 书写系统(&I) OK 确定 Apply 应用 Cancel 取消 Close 关闭 Select Font 选择字体 QFtp Not connected 没有连接 Host %1 not found 主机%1没有找到 Connection refused to host %1 连接被主机%!拒绝 Connected to host %1 连接到主机%1了 Connection refused for data connection 因为数据连接而被拒绝连接 Unknown error 未知的错误 Connecting to host failed: %1 连接主机失败: %1 Login failed: %1 登录失败: %1 Listing directory failed: %1 列出目录失败: %1 Changing directory failed: %1 改变目录失败: %1 Downloading file failed: %1 下载文件失败: %1 Uploading file failed: %1 上传文件失败: %1 Removing file failed: %1 移除文件失败: %1 Creating directory failed: %1 创建目录失败: %1 Removing directory failed: %1 移除目录失败: %1 Connection closed 连接关闭了 Host %1 found 主机%1找到了 Connection to %1 closed 到%1的连接关闭了 Host found 主机找到了 Connected to host 连接到主机了 QHostInfo Unknown error 未知的错误 QHostInfoAgent Host not found 主机未找到 Unknown address type 未知的地址类型 Unknown error 未知的错误 QHttp Unknown error 未知的错误 Request aborted 请求被放弃了 No server set to connect to 没有设置要连接的服务器 Wrong content length 错误的内容长度 Server closed connection unexpectedly 服务器异常地关闭了连接 Connection refused 连接被拒绝 Host %1 not found 主机%1没有找到 HTTP request failed HTTP请求失败 Invalid HTTP response header 无效的HTTP响应头 Invalid HTTP chunked body 无效的HTTP臃肿体 Host %1 found 主机%1找到了 Connected to host %1 连接到%1主机了 Connection to %1 closed 到%1的连接关闭了 Host found 主机找到了 Connected to host 连接到主机了 Connection closed 连接关闭了 QIODevice Permission denied 权限被拒绝 Too many open files 太多打开的文件 No such file or directory 没有这个文件或者目录 No space left on device 设备上没有空间了 Unknown error 未知的错误 QInputContext XIM XIM XIM input method XIM输入法 Windows input method Windows输入法 Mac OS X input method Mac OS X输入法 QInputDialog OK 确认 Cancel 撤销 QLineEdit &Undo 撤消(&U) &Redo 恢复(&R) Cu&t 剪切(&T) &Copy 复制(&C) &Paste 粘贴(&P) Delete 删除 Select All 选择全部 QMessageBox Help 帮助 OK 确定 Cancel 取消 &Yes 是(&Y) &No 否(&N) &Abort 放弃(&A) &Retry 重试(&R) &Ignore 忽略(&I) Yes to &All 全部是(&A) N&o to All 全部否(&O) <h3>About Qt</h3>%1<p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qtopia Core.</p><p>Qt is a Trolltech product. See <tt>http://www.trolltech.com/qt/</tt> for more information.</p> <h3>关于Qt</h3>%1<p>Qt是一个多平台图形用户界面和应用程序开发的C++工具包。</p><p>Qt提供了可以移植到MS&nbsp;Windows、Mac&nbsp;OS&nbsp;X、Linux和所有主要的Unix商业变体的单一源程序。作为Qtopia Core,Qt对于嵌入式设备也是可用的。</p><p>Qt是Trolltech的一个产品。更详细的信息请参考<tt>http://www.trolltech.com/qt/</tt>。</p> About Qt 关于Qt <p>This program uses Qt version %1.</p> <p>这个程序使用的是Qt %1版。</p> <p>This program uses Qt Open Source Edition version %1.</p><p>Qt Open Source Edition is intended for the development of Open Source applications. You need a commercial Qt license for development of proprietary (closed source) applications.</p><p>Please see <tt>http://www.trolltech.com/company/model.html</tt> for an overview of Qt licensing.</p> <p>这个程序使用的是Qt开源版本%1版。</p><p>Qt开源版本的目的是为了开发开源应用程序。如果要开发私有(不开源)应用程序,你需要一个商业的Qt许可协议。</p><p>有关Qt的许可协议请参考<tt>http://www.trolltech.com/company/model.html</tt>。</p> QNativeSocketEngine The remote host closed the connection 远端主机关闭了这个连接 Network operation timed out 网络操作超时 Out of resources 资源耗尽了 Unsupported socket operation 不被支持的套接字操作 Protocol type not supported 协议类型不被支持 Invalid socket descriptor 无效的套接字描述符 Network unreachable 网络不能访问 Permission denied 权限被拒绝 Connection timed out 连接超时 Connection refused 连接被拒绝 The bound address is already in use 要启用的地址已经被使用 The address is not available 这个地址不可用 The address is protected 这个地址被保护了 Datagram was to large to send 数据报太大,以至不能发送 Unable to send a message 不能发送一个消息 Unable to receive a message 不能接收一个消息 Unable to write 不能写入 Network error 网络错误 Another socket is already listening on the same port 另一个套接字已经正在监听同一端口 Unable to initialize non-blocking socket 不能初始化非阻塞套接字 Unable to initialize broadcast socket 不能初始化广播套接字 Attempt to use IPv6 socket on a platform with no IPv6 support 试图在不支持IPv6支持的平台上使用IPv6套接字 QObject All Files (*) 所有文件 (*) All Files (*.*) 所有文件 (*.*) Open 打开 Save As 另存为 Open 打开 Select a Directory 选择一个目录 Drive 驱动器 File 文件 Directory 目录 Symbolic Link 系统链接 Unknown 未知的 False True QPrintDialog locally connected 本地已经连接的 Aliases: %1 别名:%1 unknown 未知的 Unknown Location 未知的位置 Printer settings 打印机设置 Print in color if available 如果可能,就彩色打印 Print in grayscale 灰度打印 Print destination 打印目标 Print to printer: 打印到打印机: Print to file: 打印到文件: Browse... 浏览... Options 选项 Print all 打印全部 Print selection 打印选择 Print range 打印范围 From page: 开始页: To page: 结束页: Print first page first 先打印第一页 Print last page first 先打印最后一页 Number of copies: 份数: Paper format 纸张格式 Portrait 纵向 Landscape 横向 A0 (841 x 1189 mm) A0 (841 x 1189 毫米) A1 (594 x 841 mm) A1 (594 x 841 毫米) A2 (420 x 594 mm) A2 (420 x 594 毫米) A3 (297 x 420 mm) A3 (297 x 420 毫米) A4 (210 x 297 mm, 8.26 x 11.7 inches) A4 (210 x 297 毫米,8.26 x 11.7 英寸) A5 (148 x 210 mm) A5 (148 x 210 毫米) A6 (105 x 148 mm) A6 (105 x 148 毫米) A7 (74 x 105 mm) A7 (74 x 105 毫米) A8 (52 x 74 mm) A8 (52 x 74 毫米) A9 (37 x 52 mm) A9 (37 x 52 毫米) B0 (1000 x 1414 mm) B0 (1000 x 1414 毫米) B1 (707 x 1000 mm) B1 (707 x 1000 毫米) B2 (500 x 707 mm) B2 (500 x 707 毫米) B3 (353 x 500 mm) B3 (353 x 500 毫米) B4 (250 x 353 mm) B4 (250 x 353 毫米) B5 (176 x 250 mm, 6.93 x 9.84 inches) B5 (176 x 250 毫米,6.93 x 9.84 英寸) B6 (125 x 176 mm) B6 (125 x 176 毫米) B7 (88 x 125 mm) B7 (88 x 125 毫米) B8 (62 x 88 mm) B8 (62 x 88 毫米) B9 (44 x 62 mm) B9 (44 x 62 毫米) B10 (31 x 44 mm) B10 (31 x 44 毫米) C5E (163 x 229 mm) C5E (163 x 229 毫米) DLE (110 x 220 mm) DLE (110 x 220 毫米) Executive (7.5 x 10 inches, 191 x 254 mm) Executive (7.5 x 10 英寸,191 x 254 毫米) Folio (210 x 330 mm) Folio (210 x 330 毫米) Ledger (432 x 279 mm) Ledger (432 x 279 毫米) Legal (8.5 x 14 inches, 216 x 356 mm) Legal (8.5 x 14 英寸,216 x 356 毫米) Letter (8.5 x 11 inches, 216 x 279 mm) Letter (8.5 x 11 英寸,216 x 279 毫米) Tabloid (279 x 432 mm) Tabloid (279 x 432 毫米) US Common #10 Envelope (105 x 241 mm) 美国普通10号信封 (105 x 241 毫米) PostScript Files (*.ps);;All Files (*) PostScript文件 (*.ps);;所有文件 (*) OK 确定 Cancel 取消 Page size: 纸张大小: Orientation: 方向: Paper source: 纸张源: QProcess Unknown error 未知的错误 QProgressBar %1% %1% QProgressDialog Cancel 撤消 QRegExp no error occurred 没有错误发生 disabled feature used 使用了失效的特效 bad char class syntax 错误的字符类语法 bad lookahead syntax 错误的预测语法 bad repetition syntax 错误的重复语法 invalid octal value 无效的八进制数值 missing left delim 找不到左分隔符 unexpected end 意外的终止 met internal limit 遇到内部限制 QScrollBar Scroll here 滚动到这里 Left edge 左边缘 Top 顶部 Right edge 右边缘 Bottom 底部 Page left 左一页 Page up 上一页 Page right 右一页 Page down 下一页 Scroll left 向左滚动 Scroll up 向上滚动 Scroll right 向右滚动 Scroll down 向下滚动 QShortcut Space 空格 Esc Esc Tab Tab Backtab Backtab Backspace 退格 Return 返回 Enter 进入 Ins 插入 Del Del Pause 暂停 Print 打印 SysReq SysReq Home End 结束 Left Up Right Down PgUp PgUp PgDown PgDown CapsLock CapsLock NumLock NumLock ScrollLock ScrollLock Menu 菜单 Help 帮助 Back 后退 Forward 前进 Stop 停止 Refresh 刷新 Volume Down 调小音量 Volume Mute 静音 Volume Up 调大音量 Bass Boost 低音增强 Bass Up 调大低音 Bass Down 调小低音 Treble Up 调大高音 Treble Down 调小高音 Media Play 多媒体播放 Media Stop 多媒体停止 Media Previous 上一个多媒体 Media Next 下一个多媒体 Media Record 多媒体记录 Favorites 最喜爱的 Search 搜索 Standby 等待 Open URL 打开URL Launch Mail 启动邮件 Launch Media 启动多媒体 Launch (0) 启动 (0) Launch (1) 启动 (1) Launch (2) 启动 (2) Launch (3) 启动 (3) Launch (4) 启动 (4) Launch (5) 启动 (5) Launch (6) 启动 (6) Launch (7) 启动 (7) Launch (8) 启动 (8) Launch (9) 启动 (9) Launch (A) 启动 (A) Launch (B) 启动 (B) Launch (C) 启动 (C) Launch (D) 启动 (D) Launch (E) 启动 (E) Launch (F) 启动 (F) Print Screen 打印屏幕 Page Up 上一页 Page Down 下一页 Caps Lock 大小写锁定 Num Lock Num Lock Number Lock 数字键锁定 Scroll Lock 滚动锁定 Insert 插入 Delete 删除 Escape Escape System Request 系统请求 Select 选择 Yes No Context1 上下文1 Context2 上下文2 Context3 上下文3 Context4 上下文4 Call 呼叫 Hangup 挂起 Flip 翻转 Ctrl Ctrl Shift Shift Alt Alt Meta Meta + + F%1 F%1 QSocks5SocketEngine Socks5 timeout error connecting to socks server 连接到套接字服务器的时候,Socks5超时错误 QSql Delete 删除 Delete this record? 删除这条记录? Yes No Insert 插入 Update 更新 Save edits? 保存编辑? Cancel 取消 Confirm 确认 Cancel your edits? 取消您的编辑? QTcpServer Socket operation unsupported 套接字操作不被支持 QTextEdit &Undo 撤消(&U) &Redo 恢复(&R) Cu&t 剪切(&T) &Copy 复制(&C) &Paste 粘贴(&P) Delete 删除 Select All 选择全部 QUdpSocket This platform does not support IPv6 这个平台不支持IPv6 QUnicodeControlCharacterMenu LRM Left-to-right mark LRM 从左到右标记 RLM Right-to-left mark RLM 从右向左标记 ZWJ Zero width joiner ZWJ 零宽度连接器 ZWNJ Zero width non-joiner ZWNJ 零宽度非连接器 ZWSP Zero width space ZWSP 零宽度空格 LRE Start of left-to-right embedding LRE 开始从左到右嵌入 RLE Start of right-to-left embedding RLE 开始从右向左嵌入 LRO Start of left-to-right override LRO 开始从左向右覆盖 RLO Start of right-to-left override RLO 开始从右向左覆盖 PDF Pop directional formatting PDF 弹出方向格式 Insert Unicode control character 插入Unicode控制字符 QWhatsThisAction What's This? 这是什么? QWidget * * QWorkspace &Restore 恢复(&R) &Move 移动(&M) &Size 大小(&S) Mi&nimize 最小化(&N) Ma&ximize 最大化(&X) &Close 关闭(&C) Stay on &Top 总在最前(&T) Sh&ade 卷起(&A) %1 - [%2] %1 - [%2] Minimize 最小化 Restore Down 恢复 Close 关闭 &Unshade 展开(&U) QXml no error occurred 没有错误发生 error triggered by consumer 由消费者出发的错误 unexpected end of file 意外的文件终止 more than one document type definition 多于一个的文档类型定义 error occurred while parsing element 在解析元素的时候发生错误 tag mismatch 标记不匹配 error occurred while parsing content 在解析内容的时候发生错误 unexpected character 意外的字符 invalid name for processing instruction 无效的处理指令名称 version expected while reading the XML declaration 在读取XML声明的时候,版本被期待 wrong value for standalone declaration 错误的独立声明的值 encoding declaration or standalone declaration expected while reading the XML declaration 在读取XML声明的时候,编码声明或者独立声明被期待 standalone declaration expected while reading the XML declaration 在读取XML声明的时候,独立声明被期待 error occurred while parsing document type definition 在解析文档类型定义的时候发生错误 letter is expected 字符被期待 error occurred while parsing comment 在解析注释的时候发生错误 error occurred while parsing reference 在解析参考的时候发生错误 internal general entity reference not allowed in DTD 在DTD中不允许使用内部解析的通用实体参考 external parsed general entity reference not allowed in attribute value 在属性值中不允许使用外部解析的通用实体参考 external parsed general entity reference not allowed in DTD 在DTD中不允许使用外部解析的通用实体参考 unparsed entity reference in wrong context 没有解析的错误上下文中的实体参考 recursive entities 嵌套实体 error in the text declaration of an external entity 在一个外部实体的文本声明里有错误 mm3d-master/install-sh000077500000000000000000000220211324021725400152100ustar00rootroot00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2005-05-14.22 # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" chmodcmd="$chmodprog 0755" chowncmd= chgrpcmd= stripcmd= rmcmd="$rmprog -f" mvcmd="$mvprog" src= dst= dir_arg= dstarg= no_target_directory= usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: -c (ignored) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. --help display this help and exit. --version display version info and exit. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test -n "$1"; do case $1 in -c) shift continue;; -d) dir_arg=true shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; --help) echo "$usage"; exit $?;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t) dstarg=$2 shift shift continue;; -T) no_target_directory=true shift continue;; --version) echo "$0 $scriptversion"; exit $?;; *) # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. test -n "$dir_arg$dstarg" && break # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dstarg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dstarg" shift # fnord fi shift # arg dstarg=$arg done break;; esac done if test -z "$1"; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi for src do # Protect names starting with `-'. case $src in -*) src=./$src ;; esac if test -n "$dir_arg"; then dst=$src src= if test -d "$dst"; then mkdircmd=: chmodcmd= else mkdircmd=$mkdirprog fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dstarg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dstarg # Protect names starting with `-'. case $dst in -*) dst=./$dst ;; esac # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dstarg: Is a directory" >&2 exit 1 fi dst=$dst/`basename "$src"` fi fi # This sed command emulates the dirname command. dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` # Make sure that the destination directory exists. # Skip lots of stat calls in the usual case. if test ! -d "$dstdir"; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` shift IFS=$oIFS pathcomp= while test $# -ne 0 ; do pathcomp=$pathcomp$1 shift if test ! -d "$pathcomp"; then $mkdirprog "$pathcomp" # mkdir can fail with a `File exist' error in case several # install-sh are creating the directory concurrently. This # is OK. test -d "$pathcomp" || exit fi pathcomp=$pathcomp/ done fi if test -n "$dir_arg"; then $doit $mkdircmd "$dst" \ && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } else dstfile=`basename "$dst"` # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 trap '(exit $?); exit' 1 2 13 15 # Copy the file name to the temp name. $doit $cpprog "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && # Now rename the file to the real destination. { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ || { # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { if test -f "$dstdir/$dstfile"; then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit 1 } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" } } fi || { (exit 1); exit 1; } done # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit 0 } # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: mm3d-master/install.bat000077500000000000000000000003111324021725400153430ustar00rootroot00000000000000@echo off set MM3DDIR="c:\Program Files\Misfit Model 3D" regedit /i /s mm3d.reg mkdir %MM3DDIR% mkdir %MM3DDIR%\doc xcopy /q /y /r mm3d.exe %MM3DDIR% xcopy /q /y /r /e doc %MM3DDIR%\doc mm3d-master/man/000077500000000000000000000000001324021725400137625ustar00rootroot00000000000000mm3d-master/man/Makefile.am000066400000000000000000000002201324021725400160100ustar00rootroot00000000000000EXTRA_DIST = \ mm3d.1 all: install: $(INSTALL) -d $(DESTDIR)$(datadir)/man/man1/ ${INSTALL} -m 0644 mm3d.1 $(DESTDIR)$(datadir)/man/man1 mm3d-master/man/mm3d.1000066400000000000000000000034141324021725400147060ustar00rootroot00000000000000.TH MM3D 1 "May 31, 2007" .SH NAME mm3d \- Misfit Model 3D .SH SYNOPSIS .B mm3d .RI [ options ] " files" ... .br .SH DESCRIPTION This manual page documents briefly the .B mm3d command. .PP \fBmm3d\fP is an OpenGL\-based 3D model editor that works with triangle\-based models. It supports multi\-level undo, skeletal animations, simple texturing, scripting, command\-line batch processing, and a plugin system for adding new model and image filters. Complete online help is included. It is designed to be easy to use and easy to extend with plugins and scripts. .SH OPTIONS These programs follow the usual GNU command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the Info files. .TP .B \-h, \-\-help Print command line help and exit .TP .B \-v, \-\-version Print version information and exit .TP .B \-b, \-\-batch Batch mode (exit after processing command line) .TP .B \-s, \-\-save Save command line changes to model files .TP .B \-\-convert [format] Save models to format [format] .TP .B \-\-no-plugins Disable all plugins .TP .B \-\-no-plugin [foo] Disable plugin [foo] .TP .B \-\-sysinfo Display system information (for bug reports) .TP .B \-\-debug Display debug messages in console .TP .B \-\-warnings Display warning messages in console .TP .B \-\-errors Display error messages in console .TP .B \-\-no-debug Do not display debug messages in console .TP .B \-\-no-warnings Do not display warning messages in console .TP .B \-\-no-errors Do not display error messages in console .SH SEE ALSO .BR blender (1), .BR wings3d (1). .SH AUTHOR mm3d was written by Kevin Worcester. .PP This manual page was written by G\[:u]rkan Seng\[:u]n , for the Debian project (but may be used by others). mm3d-master/missing000077500000000000000000000254061324021725400146150ustar00rootroot00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2005-06-08.21 # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case "$1" in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file tar try tar, gnutar, gtar, then tar without non-portable flags yacc create \`y.tab.[ch]', if possible, from existing .[ch] Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). case "$1" in lex|yacc) # Not GNU programs, they don't have --version. ;; tar) if test -n "$run"; then echo 1>&2 "ERROR: \`tar' requires --run" exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then exit 1 fi ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case "$1" in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case "$f" in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison|yacc) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" y.tab.h fi ;; esac fi if [ ! -f y.tab.h ]; then echo >y.tab.h fi if [ ! -f y.tab.c ]; then echo 'main() { return 0; }' >y.tab.c fi ;; lex|flex) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if [ $# -ne 1 ]; then eval LASTARG="\${$#}" case "$LASTARG" in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if [ -f "$SRCFILE" ]; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if [ ! -f lex.yy.c ]; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` fi if [ -f "$file" ]; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit 1 fi ;; makeinfo) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; tar) shift # We have already tried tar in the generic part. # Look for gnutar/gtar before invocation to avoid ugly error # messages. if (gnutar --version > /dev/null 2>&1); then gnutar "$@" && exit 0 fi if (gtar --version > /dev/null 2>&1); then gtar "$@" && exit 0 fi firstarg="$1" if shift; then case "$firstarg" in *o*) firstarg=`echo "$firstarg" | sed s/o//` tar "$firstarg" "$@" && exit 0 ;; esac case "$firstarg" in *h*) firstarg=`echo "$firstarg" | sed s/h//` tar "$firstarg" "$@" && exit 0 ;; esac fi echo 1>&2 "\ WARNING: I can't seem to be able to run \`tar' with the given arguments. You may want to install GNU tar or Free paxutils, or check the command line arguments." exit 1 ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: mm3d-master/mkinstalldirs000077500000000000000000000066221324021725400160230ustar00rootroot00000000000000#! /bin/sh # mkinstalldirs --- make directory hierarchy scriptversion=2005-06-29.22 # Original author: Noah Friedman # Created: 1993-05-16 # Public domain. # # This file is maintained in Automake, please report # bugs to or send patches to # . errstatus=0 dirmode= usage="\ Usage: mkinstalldirs [-h] [--help] [--version] [-m MODE] DIR ... Create each directory DIR (with mode MODE, if specified), including all leading file name components. Report bugs to ." # process command line arguments while test $# -gt 0 ; do case $1 in -h | --help | --h*) # -h for help echo "$usage" exit $? ;; -m) # -m PERM arg shift test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } dirmode=$1 shift ;; --version) echo "$0 $scriptversion" exit $? ;; --) # stop option processing shift break ;; -*) # unknown option echo "$usage" 1>&2 exit 1 ;; *) # first non-opt arg break ;; esac done for file do if test -d "$file"; then shift else break fi done case $# in 0) exit 0 ;; esac # Solaris 8's mkdir -p isn't thread-safe. If you mkdir -p a/b and # mkdir -p a/c at the same time, both will detect that a is missing, # one will create a, then the other will try to create a and die with # a "File exists" error. This is a problem when calling mkinstalldirs # from a parallel make. We use --version in the probe to restrict # ourselves to GNU mkdir, which is thread-safe. case $dirmode in '') if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -p -- $*" exec mkdir -p -- "$@" else # On NextStep and OpenStep, the `mkdir' command does not # recognize any option. It will interpret all options as # directories to create, and then abort because `.' already # exists. test -d ./-p && rmdir ./-p test -d ./--version && rmdir ./--version fi ;; *) if mkdir -m "$dirmode" -p --version . >/dev/null 2>&1 && test ! -d ./--version; then echo "mkdir -m $dirmode -p -- $*" exec mkdir -m "$dirmode" -p -- "$@" else # Clean up after NextStep and OpenStep mkdir. for d in ./-m ./-p ./--version "./$dirmode"; do test -d $d && rmdir $d done fi ;; esac for file do case $file in /*) pathcomp=/ ;; *) pathcomp= ;; esac oIFS=$IFS IFS=/ set fnord $file shift IFS=$oIFS for d do test "x$d" = x && continue pathcomp=$pathcomp$d case $pathcomp in -*) pathcomp=./$pathcomp ;; esac if test ! -d "$pathcomp"; then echo "mkdir $pathcomp" mkdir "$pathcomp" || lasterr=$? if test ! -d "$pathcomp"; then errstatus=$lasterr else if test ! -z "$dirmode"; then echo "chmod $dirmode $pathcomp" lasterr= chmod "$dirmode" "$pathcomp" || lasterr=$? if test ! -z "$lasterr"; then errstatus=$lasterr fi fi fi fi pathcomp=$pathcomp/ done done exit $errstatus # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-end: "$" # End: mm3d-master/mm3d-win32-installer.nsi000066400000000000000000000105611324021725400175200ustar00rootroot00000000000000; Misfit Model 3D - NSI Script (Installer Script) ; ; Copyright (c) 2004-2007 Kevin Worcester ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program; if not, write to the Free Software ; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, ; USA. ; ; See the COPYING file for full license text. !define VERSION "1.3.9" !define FILE_VERSION "1_3_9" Name "Misfit Model 3D ${VERSION}" OutFile "mm3d-${FILE_VERSION}-win32-installer.exe" SetCompressor lzma Icon src\pixmap\mm3dlogo-32x32.ico UninstallIcon src\pixmap\mm3dlogo-32x32.ico BrandingText "Misfit Model 3D" CRCCheck on XPStyle on InstallDir "$PROGRAMFILES\Misfit Model 3D" InstallDirRegKey HKCU "Software\Misfit Code\Misfit Model 3D" "INSTDIR" LicenseData COPYING Page license Page components Page directory Page instfiles UninstPage uninstConfirm UninstPage instfiles Section "Misfit Model 3D" SectionIn RO ; Create file type WriteRegStr HKCR "MisfitCode.Mm3dModelFile" "" "MM3D Model File" WriteRegStr HKCR "MisfitCode.Mm3dModelFile\shell\open\command" "" '"$INSTDIR\mm3d.exe" "%1"' WriteRegStr HKCR "MisfitCode.Mm3dModelFile\shell\edit" "" "Edit Model" WriteRegStr HKCR "MisfitCode.Mm3dModelFile\shell\edit\command" "" '"$INSTDIR\mm3d.exe" "%1"' SetOutPath "$INSTDIR" WriteRegStr HKCU "Software\Misfit Code\Misfit Model 3D" "INSTDIR" "$INSTDIR" File COPYING File mm3d.exe File /r /x .svn /x *.htm /x Makefile /x Makefile.* /x *.ts doc imageformats i18n File dll\*.dll WriteUninstaller "Uninstall.exe" SectionEnd Section "Start Menu Shortcuts" ; SetShellVarContext all CreateDirectory "$SMPROGRAMS\Misfit Model 3D" CreateShortcut "$SMPROGRAMS\Misfit Model 3D\Misfit Model 3D.lnk" "$INSTDIR\mm3d.exe" CreateShortcut "$SMPROGRAMS\Misfit Model 3D\Help Documentation.lnk" "$INSTDIR\doc\html\olh_index.html" CreateShortcut "$SMPROGRAMS\Misfit Model 3D\License.lnk" "$INSTDIR\doc\html\olh_license.html" CreateShortcut "$SMPROGRAMS\Misfit Model 3D\MM3D Web Page.lnk" "https://clover.moe/mm3d" CreateShortcut "$SMPROGRAMS\Misfit Model 3D\Uninstall.lnk" "$INSTDIR\Uninstall.exe" SectionEnd SubSection /e "Associate file types" Section "MM3D (Misfit Model 3D)" WriteRegStr HKCR ".mm3d" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "Cal3d" WriteRegStr HKCR ".cal" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "COB (Truespace)" WriteRegStr HKCR ".cob" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "DXF (Autocad DXF)" WriteRegStr HKCR ".dxf" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "LWO (Lightwave)" WriteRegStr HKCR ".lwo" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "MS3D (Milkshape)" WriteRegStr HKCR ".ms3d" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "MD2 (Quake)" WriteRegStr HKCR ".md2" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "MD3 (Quake)" WriteRegStr HKCR ".md3" "" "MisfitCode.Mm3dModelFile" SectionEnd Section /o "OBJ (Alias Wavefront)" WriteRegStr HKCR ".obj" "" "MisfitCode.Mm3dModelFile" SectionEnd SubSectionEnd Section "Uninstall" Delete "$INSTDIR\mm3d.exe" Delete "$INSTDIR\mingw*.dll" Delete "$INSTDIR\qt*.dll" Delete "$INSTDIR\COPYING" Delete "$INSTDIR\Uninstall.exe" RMDir /r /REBOOTOK "$INSTDIR\doc" RMDir /r /REBOOTOK "$INSTDIR\i18n" RMDir /r /REBOOTOK "$INSTDIR\plugins" RMDir /r /REBOOTOK "$INSTDIR\userhome" RMDir /r /REBOOTOK "$INSTDIR\imageformats" RMDir $INSTDIR ; SetShellVarContext all RMDir /r /REBOOTOK "$SMPROGRAMS\Misfit Model 3D" DeleteRegKey HKCR "MisfitCode.Mm3dModelFile" SectionEnd mm3d-master/mm3d.icns000066400000000000000000002530251324021725400147340ustar00rootroot00000000000000icnsVic089PNG  IHDR\rf iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o5IDATxYmZ7"D0&^;0cs# 1AM4 /sri#x#?0I߉ZOջ=\sUj5Hj}xf99ku t:@g3 t:@g3 t:@g639qY/'./}{u:;w:o+_89|rvI;ךy,Gsx݅φ~V_5]S5 ).G 0/} H{'i`Woٵ  |b)k[ϻ>oLw` /&3Rw ;gNt'rqIM獇%[0?5cBJ񧟛{ ԟO? :Ȁ ]ktyvӧ76uwwI+>L<ؿN<")ߙm.I./3x\'Of"73, w{'Ν"wzO5L[Prǯutꑹ'/w};KnF|˼߅PNv$ybuzkz'5%ut#Y,b.?^#qß.7|}i,oҽ qO6Nvᑉ9SIf9Ěű96F=˳ӏ*Odq.aog >x'uf?ɾ}M'=2' PX s0~ üf})'/O߲lz~qpGrѯboݙ̏;ĶK y$_\ oӀpa \"E>ட{pܽiÍ]O~xM]&~nLz/-8OKw>_*Ջ.u,K\b~؏t#c *F:ap /ObYrԓۇGz8&3b';R' \~z/?{9±uO:eEl >6tm'zomb'+z깻#[8o ԓ+:2z侢h'W^\u@͓}? X,?9%}3Stޅˏ9L^qJ'5|rCh́EPK}69f Cԓ#6EϞH\c}].t:1O^iOm`p4\w]<J9vwmS~MqW' ۺ#G;\# %!_%ǁK A.=e 3^-HiN߲ln)K}bsoOѶֵyt&ùKW=zq!ڮo;׋}Pi?ެ{\6^ȭ,y[ 9SS~9ysRd'n匁sCxS܂i2{:tbDO\'}+Lt9<бPX~=>T -wgോ /OⰓ>}D+>R\E ?!R\>l''],'wwG@> ~>gy:\.bJp< NV5Ё;̀{I6>opC:ygWl ];6:8mi '8m'kmb|b@ v'Oj.1gmġT ] }Smv9ai|Ϥ-uW9ofk Y9>[1rS{?c:k|cP#s{i֪\ OYLb}."ݪ٫Ձ:@g3p}ov~_w}OWL+ʝ<|bʥmڈS&N>pQcޝ7glO6b&.t@g3'_Xvw~cN^Hʝw)Nۊu$qg$#~bsmmR3[䑎6<%ĩ @_%| v0*O*7<2ybTN[W?r}Nms=;gr1`,,w& v]UxUv t3n:gkHޟio^?>+?@ʃ_X]sq3?Xxj/ɭat[Iz玮רڪ^_bQxo~rb'IYώcxgObfI]1~@py G6[lO2c mQWl<'91m?#%y;9Ŵe{H~>>cma- N>}w t,}8%5{7ѹם~)f'#sgqg KY dI;ywE/]bwo^C;W("OL8_~s2A6rj3~cg{ OkhȼHq&N}bm\B>%?e$Eا>I @;ӎ2><2cxop̱JX1;Ng3p%p^f7@r]SìʮJvwpZc%6ι;¦Lm0蓧+rkQg:Hʚ凟z~b'1rgvB m"㇞J4ɓZ囂v}u;kD;~h"2cKI5X>[W|UV۬;9.붱Eg\}w;&y$MjӞ l?p$i8i@gF2u#s]YQ]UY]SGbTFS7i#Vb_qgLtkz+jk#ў:%YxH=8}OL]6ۆ^C/asbf]rF&?{\;k赙ظ(Rl tn$}8p M+7;GJW]d#lЍk|gUGUmᬫ>916pbZR_Wb'z2mx "< x PpoS #u\uӯb*g^=r_nG\Dxn;u䴫|K%z1;ھ2qHɎ$۶ tn,.7v/?^y`v%E&vO'K=,Fn#Xշg<8vI9wLxZGκz,od[ڧ-mW}x>Կy4a`Iq0 JWi^?t媞:j_jXj.O[T9s%8mİ_k(']-yoְ`/mcŤUf'|E WZ++)܌bЍlӯb[cKIGf0>ĵ:XUgi '6~Kjo}~p{)&I½z=1o5<Dg/&E;7bmr)+UWmk_hޢmrX"k!V/qƟiS1>Y2FbmᑭRwf >^3&^@gN3FeOMI vWl uJ} ~ƶm=S?i&l`QmfxևC}q?8#i@g3v˫OsO++mr[1٢#3L3ljInIH١swML8Y6KU1HceAz_#VzXN ɯ݁H>~H1˥>q^-zJJcֺQ_)G~Ԗ.Ɖ/g]N1ӏlI}Fzuȼﰭ wV'Ag3p?XypŬo3LSĵnwSqic}1F8cp Wʥ>16YF3^bK~&g~suYfޯ$POXx~)сLj{_3 }Su`'8vfHk6c'1O^n$Ӗ`d :7 pzX\NITZw=z̰3zKb*WkLXiIƥnOoUzZluHO_ 2}Gϳ($A drɋ MO?M>qƃ_+i[:-Fr=iS1vG:^az}7}viC罪]@g2pugߗԓG&^uY'4Hjf\껦{mƬ;um֌O}Q7xɉG[X}G?^D>CoId;0U&kQ}6k[u_}zbc?GpmMnXS~闲7mFx~&@g2'2l}?-n#5]OL1M?6On*gS}oicRɘpa_&v}zg2'2خE:Zٷr[ Vep3Y:񾶱bc<%>#eMo?3{4~0l]ڊ"ߓk>. XZY߶l FU7z/)GqgꍻGj-}f띁;@? !+u&fK=X[Wym:8V;ӖzUV+jŕnkoۏ!g}ZtdbeHߏdKgN3pdUs;ѕ⣟2*Wi Va}rŗC7ӧ xdglg<~?zRON4>i=5O?̶Yv7 P)wg-vdGmgv)?3nW~O5KG׌M?.;@VUSbV{%8uk?}>Q7'ecdc\uǧ>L^H1g,u'?>rֳ Y;/G?SX:vp+6uAyhZW#h `e]=s_1߬2n:'$4ƞ鉝6mwX~x('~˺p(U#5oleW'w(}XlWMdRi5vɭP?A;;>3N[k^mSt[M''Vҗ>>)yx2}*ζz/LxENxXRxڨե?x q\b%vଧXk5U5?T]J첽ԉL a|x)uV_u8h2]-6~g{$'&9xz#Y?XH_Z7nͰUO?L >jICN fr3j[k}G^Y\;[dzbeZGb7NY.eulSG/wH?c\|8#Q1pRжk_c^N}uԖzG|r\ӏtɉg=۪j_rO&Orb& ',_~d4 [0qV\WĮHq˧+m&tc؇:m:Mgܪ&x~WκR?Jy]&&7jr&/+%cr0NRc:mUnz|k,!)bMXG&?_yÎ/)pڋyPȖ{̀'W^;xe'p{T+u+Uz'/3% }$|i~WO&Kկ٦~疣Nz~{#-eg3pM1|RĮ=Fr3[K>7W[3Xd岮uiK}쳝UoY[O[uUlӯ3B^D{ 0NCSw 码DI7Balkqr>i>u}6Y3Saj&OƭݗnV,pԮ#Gi3pG`E 寿[WeW\Җ2m;cƳxWR}:>K&~.}a5۴Qs,>qo$=2hwc%8HN9CcUӂ^{9d%??3*O762}H.qg<6R!#y?Amo|fOW/+1/])]uS_wdw%6]ʝ6HlqTW>)5O>N~ mڌ .c%}'< |.ȏIG:#NX!S''V]bJuW=LOG*Տ|zb3lgq(ɝ 0M̆ Å|Vun=GxxW_M~y |ѣxZRS~'%lX{ڱ'O.V$^IP7S7OHmKOH bbs3g{>1EoMaҕ_$$A ILT\el?GG>bkCy#FXCuiOc1F뷥W:S,<fߺ@g2'C/} ,?U9WqWplF?ڔN`G]=u1z)꡸3+g_cP7:R8[G&67pڦ }DiH1v5[_{֟]eOw p@] Mw'D&vG;OnQ?rw϶刕XYyg?W>7NbSd?2N^^b̯;H.\N-8F7 wa+NLAVOA7!SoknVlbs='`~Om3F/m?}8tg=j@g2'Gw/2KwB'GWvKix>=2a_%:y娋S=D~#LLlͩ?197R?yboCL(y!2H3Ndbo@'pihc=QhC{b[Ͼ:6#=|PeM_uԓIlXdbL=12m3N= Jޗ/po@g3''_~ɂ]sgvtn֑q(WV䕩K{}zL8ɗ:dbɥ- 6b 1)w<#N?z{qL{)ʯ_ u9e[fU}֝doF ҉\bω/!C4 ULC{`v t?n:%opk.vUbLԁsK:y8w+̰~wV{%~N|A\:2W+p61|bl(psׯ| @Iߗ^^vQ/1 4E݉Bݒ\bHy7`3lIlSg.]AGIudƦ^K>}xMiNGԋ2upo]x$ay$^9i@g3'#/1<U)vDG\+6.]es;a8E'c+[vG#Nb|ȕaF?wz>w~f'9:la_\zxqbyoX@N%9ڳ~y:6Cޛ1Gb|0gCiO,ۇ#PVN9N\ Lv;_#OCu:א>i)V\W];%:29K![LM=/ W:[Q7vouڏYGz)k |b@]~ 8}sh/#u@g2'#.v>]nmdqJ̻O;pٶ6\茕x?3G֒vZO5~izSΰ1k3ѹ#gxQ=<{w|08AysOp P79lZIozCcGrơ튍n>c=q(rĩqb으;#`ccv@ۜ`)z&g>L=8G A: Nugo.Rz9:w9VģX=1ܭr6*oQ txw?6vN 7|b8yx)+'_[e#Ĝat~o?<~&W6J䚴Czr X=u&;~?] t }8 ×7߽+;_ϺQg7N]1,.&o?/OE{ĵO&>>[Oxf˵bgzw{8wC8t먥s/rp;N7Z,N;&~'F7 R}(rT?j?RXۙ+Ly}럶6';~.Ô$q=I \vpݣ_\\u箂t`;\& 6;[I~piTTŏ3-k&:#Ŗ|ӧ>O (ghX2n1boP*;H~N^8y&퀝&WmYܞcQamSڷ>Eizg)fr;G=00},t#4-iKi[蝁eOo0$ǁn#0L].wsyX]Ν"ഡnI }rK^~&ylC&>1~yBa}~44Zȝfk&:?{;PRbLO_O 3[FL>zա!ygFX9ùnON]g0^ʏ|G>\Уm3/n^݌b+;z&NdQEA;q]֑ɍ͡<>pz^+2qc$ qba_-v:o77ȽwG=%X)`[3!Pxpgv'N\OAg 8ybP^8ˌfp\ôWyO;?~]{?L¼mx^tϻO, Wr2@U:]uQK}5%Ĵx-#n6lĩ9G _aW}Y9_Dgy3&qV ݻ?bl~?A]v#yN!a.xoO>mG|hNѢLȄ;.pbˈStbq3'zbc(ɛH&2cy^u:'̀ƞF^7{B߄3g\=w"wX)U/tWpǮ{kOwzաk[G8y%'cxbɳǧ]WQ2p:3Si E)Jg]ډQPO`LHwWw}=Pz2#.쮹x?\5}m-,>7,8؅?ZI?Kz 1m׉ ]G˼ Ժ_`׺K3"v:2c#h@_ 썐؝2Oԉ؂uٺk@ߵa~^}OZjYۼ;Vn`?;@4[ '$(,])m^~䱞=@Vä#%|,%#Sߞ@/gz~x4 MNxؒ>%l)G@[n^$[l__kOZG8BWbˮdj2p'}-pC ;-Y>\${GۻǝeN'}^N }{{ O 9-\ `kW7Gp/GNs_^] +}8WIa ஗5`. |#}Nz\k켍6~8f6;Vg20yX~Aps9{#@~8OivDf'}YwBO x\}^ -޷H%ǵٲHbs8n6Z?mfNy A>)-'[:%Ofeg3p'#vR,n)ZN3sP\]"1[nK@{?\߽ %Wp=FO f|rc=9)aR?%ӽ@%' u7ooL apASR8%no'ME7Kk%Y=?^+.mD?3fOgLzSNx)a=L`&B[$zaN# Fw3p ?i{N4ާCp F,-@@o~ؔ6 fpwB n '3Ѳ3p᠟>q?;ݏf3ЏGLIC#I;>\pqn^nx][ s/םQ`:w- }^–}f3 t:@g3 t:@g3 'YBIENDB`ic11 PNG  IHDR szz iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o4IDATX ͖k\UO~7I4MJQ֝_ qBAqUARRЍ•ƍ]U!46HҘLf~{$u|s3l^ w=*+@ˮغ6ʞ8flئUِkgݵ}Um aŶcἝl0)c₝̶5mV ж?st )F)RO[b % jJlX^Al1;!T"tJʩesC9=zJa.d0p'=!ȬMK!)P hWhD#WNKcwaԒp]9@ k7hOl!ga XmPE+ 9"nV\@dX؍d`)^>N2$3u_s0AK0LNб5TA_*K,ǚ JUF 4#1<:}YtRHrZtƐ5hE B$}äRa!_"Rʕzʹ,W:9o}G?@5rm5R;9J`+m)^wCqN  @FPJ5MJS'%MU؍OA;o=Wq mwG 8[`csrL7hێpV˺m}!8.!K8!@@) V|϶JSPgSiAN֍7+!vKɣcy ڷJ hū+b<ߌGСf?Z R-lue}٣bO7 ^CX P>ߑ7J8ͧ}gy{R!R|%{%Ia_ ]gn`4Ϸ͖}mg} Αd ./9?U3Ѩl"hDy d+b/O>;W.k Ӊ% ۏ6٧#w Ә_ėyDJNIuG>[+'׭%T!g۪Yu@)KtLi Q>i}X[|evѦ2( 1̴BMڵߺxϘ8 c32|=8@)Yq̎-?܍sӾ:290=5Wm#vHq Grޛzj_v&B? ®0IENDB`ic12 PNG  IHDR@@iq iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o IDATxYdUwwC4!("}2qH4> >hH0*11q *j">  2+*Cah@߹ZS}DJ]kpNUu.le`FoF<_~bD~vk+OIWWxB#ܖ>}4}6B>%։edB( !#@T͔UOö sp \, 4D<2K"$`{t $|tQFh!+^#E%X@@]}Y(/I8'I7CV pT]N݀3zg4˴[" *LxUd6 VKG+pjMz${o9 - 0yDYy2%hVe!@ xF4|dR@@/H=Qvâ#.K"aj6ט."Q=cB5Ʋ(ljK>3gVKAfґq鲩^5xhz3oҀ<;@_띠eGkkB%"\7)6R4d`FV#˧1 Q%c3}Iʉ5[krQSxo{I^%SVIXc8 _TP/@#:'sSݽ u%co38|vEMqCY[Wڙ'mjZ Q4yV}댣luZ<} ď?')fJ{cwM&]A-W߶4{$sXONkw%5xvAmW;:۟Ib>V"D"X-}kx5]@s γwp"UQTk;kҷmuպ;g^yO+\uPS[Wk>sy,Wkl<$؝!+N5 nHOQbIDwtC [>)5I|17}ͱBgIkDbꡛIclJ*ec(,X^%oWk'kgl۶Zg2}A傍N^saAXw?6eM!>?$nȸ9:! bz5Y7&:cVx|}+j[_<l״DL;M8|c/~ٮ`GOȂ#4 9_c nkv8!=a~Yjh^} x 2D9{kUi]e̗!7c~'%kiï1@ȦO_q~7PoַgNJc[Ҁesr:Wխ0QT/p+xC9O@̇m:x *0V '0bhc\X6%UF䗀 9`#!G.(|NѺ-P {@ɉ2wϤ>h!eW\}s냄ԗ9 3ou$8 Q Xo1>xH+e Lv(?m.#_ I " ABlU%wKY}>Ouv޲Nok/1\=ʈ+^Ǒ> WϿ% n뷷hf7}DQ@b}胸 x%u[?՝qt@*/uV.v~V W>nZ{O< Osv@KHI ~^#yY޹vS?OVY$S\׬z=]lkW˼ u<#(:6U۶b]N gKOZ4ZX ؞/G%0}z)Lʫ1YC/BʩgGD!ȨG^s֥yPCBVp MJ/ JbgR)vv릥D!(sqlNU*~aMC 2 12B~;?J8+e>E5,x$[AxQ(B?'YXp8ɫRw[(1<-ڸswfLwYG!(,o4e4K KQvuQVQ>c$Fy9;9N9ԝ^KyL!? C8'@!BP|V(;QV "eJN (N="ZBfM!I'bn" ^ZF (;30 7lAi6ѥItwGEPw [1326>п ?m=IENDB`ic139PNG  IHDR\rf iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o5IDATxYmZ7"D0&^;0cs# 1AM4 /sri#x#?0I߉ZOջ=\sUj5Hj}xf99ku t:@g3 t:@g3 t:@g639qY/'./}{u:;w:o+_89|rvI;ךy,Gsx݅φ~V_5]S5 ).G 0/} H{'i`Woٵ  |b)k[ϻ>oLw` /&3Rw ;gNt'rqIM獇%[0?5cBJ񧟛{ ԟO? :Ȁ ]ktyvӧ76uwwI+>L<ؿN<")ߙm.I./3x\'Of"73, w{'Ν"wzO5L[Prǯutꑹ'/w};KnF|˼߅PNv$ybuzkz'5%ut#Y,b.?^#qß.7|}i,oҽ qO6Nvᑉ9SIf9Ěű96F=˳ӏ*Odq.aog >x'uf?ɾ}M'=2' PX s0~ üf})'/O߲lz~qpGrѯboݙ̏;ĶK y$_\ oӀpa \"E>ட{pܽiÍ]O~xM]&~nLz/-8OKw>_*Ջ.u,K\b~؏t#c *F:ap /ObYrԓۇGz8&3b';R' \~z/?{9±uO:eEl >6tm'zomb'+z깻#[8o ԓ+:2z侢h'W^\u@͓}? X,?9%}3Stޅˏ9L^qJ'5|rCh́EPK}69f Cԓ#6EϞH\c}].t:1O^iOm`p4\w]<J9vwmS~MqW' ۺ#G;\# %!_%ǁK A.=e 3^-HiN߲ln)K}bsoOѶֵyt&ùKW=zq!ڮo;׋}Pi?ެ{\6^ȭ,y[ 9SS~9ysRd'n匁sCxS܂i2{:tbDO\'}+Lt9<бPX~=>T -wgോ /OⰓ>}D+>R\E ?!R\>l''],'wwG@> ~>gy:\.bJp< NV5Ё;̀{I6>opC:ygWl ];6:8mi '8m'kmb|b@ v'Oj.1gmġT ] }Smv9ai|Ϥ-uW9ofk Y9>[1rS{?c:k|cP#s{i֪\ OYLb}."ݪ٫Ձ:@g3p}ov~_w}OWL+ʝ<|bʥmڈS&N>pQcޝ7glO6b&.t@g3'_Xvw~cN^Hʝw)Nۊu$qg$#~bsmmR3[䑎6<%ĩ @_%| v0*O*7<2ybTN[W?r}Nms=;gr1`,,w& v]UxUv t3n:gkHޟio^?>+?@ʃ_X]sq3?Xxj/ɭat[Iz玮רڪ^_bQxo~rb'IYώcxgObfI]1~@py G6[lO2c mQWl<'91m?#%y;9Ŵe{H~>>cma- N>}w t,}8%5{7ѹם~)f'#sgqg KY dI;ywE/]bwo^C;W("OL8_~s2A6rj3~cg{ OkhȼHq&N}bm\B>%?e$Eا>I @;ӎ2><2cxop̱JX1;Ng3p%p^f7@r]SìʮJvwpZc%6ι;¦Lm0蓧+rkQg:Hʚ凟z~b'1rgvB m"㇞J4ɓZ囂v}u;kD;~h"2cKI5X>[W|UV۬;9.붱Eg\}w;&y$MjӞ l?p$i8i@gF2u#s]YQ]UY]SGbTFS7i#Vb_qgLtkz+jk#ў:%YxH=8}OL]6ۆ^C/asbf]rF&?{\;k赙ظ(Rl tn$}8p M+7;GJW]d#lЍk|gUGUmᬫ>916pbZR_Wb'z2mx "< x PpoS #u\uӯb*g^=r_nG\Dxn;u䴫|K%z1;ھ2qHɎ$۶ tn,.7v/?^y`v%E&vO'K=,Fn#Xշg<8vI9wLxZGκz,od[ڧ-mW}x>Կy4a`Iq0 JWi^?t媞:j_jXj.O[T9s%8mİ_k(']-yoְ`/mcŤUf'|E WZ++)܌bЍlӯb[cKIGf0>ĵ:XUgi '6~Kjo}~p{)&I½z=1o5<Dg/&E;7bmr)+UWmk_hޢmrX"k!V/qƟiS1>Y2FbmᑭRwf >^3&^@gN3FeOMI vWl uJ} ~ƶm=S?i&l`QmfxևC}q?8#i@g3v˫OsO++mr[1٢#3L3ljInIH١swML8Y6KU1HceAz_#VzXN ɯ݁H>~H1˥>q^-zJJcֺQ_)G~Ԗ.Ɖ/g]N1ӏlI}Fzuȼﰭ wV'Ag3p?XypŬo3LSĵnwSqic}1F8cp Wʥ>16YF3^bK~&g~suYfޯ$POXx~)сLj{_3 }Su`'8vfHk6c'1O^n$Ӗ`d :7 pzX\NITZw=z̰3zKb*WkLXiIƥnOoUzZluHO_ 2}Gϳ($A drɋ MO?M>qƃ_+i[:-Fr=iS1vG:^az}7}viC罪]@g2pugߗԓG&^uY'4Hjf\껦{mƬ;um֌O}Q7xɉG[X}G?^D>CoId;0U&kQ}6k[u_}zbc?GpmMnXS~闲7mFx~&@g2'2l}?-n#5]OL1M?6On*gS}oicRɘpa_&v}zg2'2خE:Zٷr[ Vep3Y:񾶱bc<%>#eMo?3{4~0l]ڊ"ߓk>. XZY߶l FU7z/)GqgꍻGj-}f띁;@? !+u&fK=X[Wym:8V;ӖzUV+jŕnkoۏ!g}ZtdbeHߏdKgN3pdUs;ѕ⣟2*Wi Va}rŗC7ӧ xdglg<~?zRON4>i=5O?̶Yv7 P)wg-vdGmgv)?3nW~O5KG׌M?.;@VUSbV{%8uk?}>Q7'ecdc\uǧ>L^H1g,u'?>rֳ Y;/G?SX:vp+6uAyhZW#h `e]=s_1߬2n:'$4ƞ鉝6mwX~x('~˺p(U#5oleW'w(}XlWMdRi5vɭP?A;;>3N[k^mSt[M''Vҗ>>)yx2}*ζz/LxENxXRxڨե?x q\b%vଧXk5U5?T]J첽ԉL a|x)uV_u8h2]-6~g{$'&9xz#Y?XH_Z7nͰUO?L >jICN fr3j[k}G^Y\;[dzbeZGb7NY.eulSG/wH?c\|8#Q1pRжk_c^N}uԖzG|r\ӏtɉg=۪j_rO&Orb& ',_~d4 [0qV\WĮHq˧+m&tc؇:m:Mgܪ&x~WκR?Jy]&&7jr&/+%cr0NRc:mUnz|k,!)bMXG&?_yÎ/)pڋyPȖ{̀'W^;xe'p{T+u+Uz'/3% }$|i~WO&Kկ٦~疣Nz~{#-eg3pM1|RĮ=Fr3[K>7W[3Xd岮uiK}쳝UoY[O[uUlӯ3B^D{ 0NCSw 码DI7Balkqr>i>u}6Y3Saj&OƭݗnV,pԮ#Gi3pG`E 寿[WeW\Җ2m;cƳxWR}:>K&~.}a5۴Qs,>qo$=2hwc%8HN9CcUӂ^{9d%??3*O762}H.qg<6R!#y?Amo|fOW/+1/])]uS_wdw%6]ʝ6HlqTW>)5O>N~ mڌ .c%}'< |.ȏIG:#NX!S''V]bJuW=LOG*Տ|zb3lgq(ɝ 0M̆ Å|Vun=GxxW_M~y |ѣxZRS~'%lX{ڱ'O.V$^IP7S7OHmKOH bbs3g{>1EoMaҕ_$$A ILT\el?GG>bkCy#FXCuiOc1F뷥W:S,<fߺ@g2'C/} ,?U9WqWplF?ڔN`G]=u1z)꡸3+g_cP7:R8[G&67pڦ }DiH1v5[_{֟]eOw p@] Mw'D&vG;OnQ?rw϶刕XYyg?W>7NbSd?2N^^b̯;H.\N-8F7 wa+NLAVOA7!SoknVlbs='`~Om3F/m?}8tg=j@g2'Gw/2KwB'GWvKix>=2a_%:y娋S=D~#LLlͩ?197R?yboCL(y!2H3Ndbo@'pihc=QhC{b[Ͼ:6#=|PeM_uԓIlXdbL=12m3N= Jޗ/po@g3''_~ɂ]sgvtn֑q(WV䕩K{}zL8ɗ:dbɥ- 6b 1)w<#N?z{qL{)ʯ_ u9e[fU}֝doF ҉\bω/!C4 ULC{`v t?n:%opk.vUbLԁsK:y8w+̰~wV{%~N|A\:2W+p61|bl(psׯ| @Iߗ^^vQ/1 4E݉Bݒ\bHy7`3lIlSg.]AGIudƦ^K>}xMiNGԋ2upo]x$ay$^9i@g3'#/1<U)vDG\+6.]es;a8E'c+[vG#Nb|ȕaF?wz>w~f'9:la_\zxqbyoX@N%9ڳ~y:6Cޛ1Gb|0gCiO,ۇ#PVN9N\ Lv;_#OCu:א>i)V\W];%:29K![LM=/ W:[Q7vouڏYGz)k |b@]~ 8}sh/#u@g2'#.v>]nmdqJ̻O;pٶ6\茕x?3G֒vZO5~izSΰ1k3ѹ#gxQ=<{w|08AysOp P79lZIozCcGrơ튍n>c=q(rĩqb으;#`ccv@ۜ`)z&g>L=8G A: Nugo.Rz9:w9VģX=1ܭr6*oQ txw?6vN 7|b8yx)+'_[e#Ĝat~o?<~&W6J䚴Czr X=u&;~?] t }8 ×7߽+;_ϺQg7N]1,.&o?/OE{ĵO&>>[Oxf˵bgzw{8wC8t먥s/rp;N7Z,N;&~'F7 R}(rT?j?RXۙ+Ly}럶6';~.Ô$q=I \vpݣ_\\u箂t`;\& 6;[I~piTTŏ3-k&:#Ŗ|ӧ>O (ghX2n1boP*;H~N^8y&퀝&WmYܞcQamSڷ>Eizg)fr;G=00},t#4-iKi[蝁eOo0$ǁn#0L].wsyX]Ν"ഡnI }rK^~&ylC&>1~yBa}~44Zȝfk&:?{;PRbLO_O 3[FL>zա!ygFX9ùnON]g0^ʏ|G>\Уm3/n^݌b+;z&NdQEA;q]֑ɍ͡<>pz^+2qc$ qba_-v:o77ȽwG=%X)`[3!Pxpgv'N\OAg 8ybP^8ˌfp\ôWyO;?~]{?L¼mx^tϻO, Wr2@U:]uQK}5%Ĵx-#n6lĩ9G _aW}Y9_Dgy3&qV ݻ?bl~?A]v#yN!a.xoO>mG|hNѢLȄ;.pbˈStbq3'zbc(ɛH&2cy^u:'̀ƞF^7{B߄3g\=w"wX)U/tWpǮ{kOwzաk[G8y%'cxbɳǧ]WQ2p:3Si E)Jg]ډQPO`LHwWw}=Pz2#.쮹x?\5}m-,>7,8؅?ZI?Kz 1m׉ ]G˼ Ժ_`׺K3"v:2c#h@_ 썐؝2Oԉ؂uٺk@ߵa~^}OZjYۼ;Vn`?;@4[ '$(,])m^~䱞=@Vä#%|,%#Sߞ@/gz~x4 MNxؒ>%l)G@[n^$[l__kOZG8BWbˮdj2p'}-pC ;-Y>\${GۻǝeN'}^N }{{ O 9-\ `kW7Gp/GNs_^] +}8WIa ஗5`. |#}Nz\k켍6~8f6;Vg20yX~Aps9{#@~8OivDf'}YwBO x\}^ -޷H%ǵٲHbs8n6Z?mfNy A>)-'[:%Ofeg3p'#vR,n)ZN3sP\]"1[nK@{?\߽ %Wp=FO f|rc=9)aR?%ӽ@%' u7ooL apASR8%no'ME7Kk%Y=?^+.mD?3fOgLzSNx)a=L`&B[$zaN# Fw3p ?i{N4ާCp F,-@@o~ؔ6 fpwB n '3Ѳ3p᠟>q?;ݏf3ЏGLIC#I;>\pqn^nx][ s/םQ`:w- }^–}f3 t:@g3 t:@g3 'YBIENDB`ic14WPNG  IHDRx iCCPICC Profile8U]hU>sg#$Sl4t? % V46nI6"dΘ83OEP|1Ŀ (>/ % (>P苦;3ie|{g蹪X-2s=+WQ+]L6O w[C{_F qb Uvz?Zb1@/zcs>~if,ӈUSjF 1_Mjbuݠpamhmçϙ>a\+5%QKFkm}ۖ?ޚD\!~6,-7SثŜvķ5Z;[rmS5{yDyH}r9|-ăFAJjI.[/]mK 7KRDrYQO-Q||6 (0 MXd(@h2_f<:”_δ*d>e\c?~,7?& ك^2Iq2"y@g|UP`o@IDATx_mUBi T c⥯#1 h#0 ;Ϟyhs_7/Kg E}H@$VCkb H@~ تzuo+ *)u =he7%^,Y.clӦ l65ͭ5UMH@$pg>X^$ptݣNjm  Eyl9+cK9^f=,?x7QyEǭ p'4Gdj%  H@8vÜ$  H` -@90?g{?++$ZvԫĄl7_3揘l4s}6H\K$  <&j H@xp:_n4EG-F?wQdCk1լqafzNK46m/GI@$pW蔀$  a^[;vi<-fQ;ҌOc{K_g1ڣ>_\>^[ܞNoӗ$  B[# H@88n<@*uk #s4QZkufWKԭmzv:TZԳ*mdﺼe<$  H@|%^$p츝`9#Kp Eּ$ `7m\cjnTl3WM*6?8sGc^vPOyT+Q_SC?qp{|w&V$  H`3>lB$ `?™H@6#omV@:!4ߧUɧ}燄״~Dl⧦bG=}L?y*1M6'~=zڌ6iW41c~/DhE/UǼ$  숀;NE$vͶ:nv#ۗ>.0[1_g ?'1!B;Kf mlKsR}˼/|E5?[I{ڌvxm Ks =67$  QNS$$vӖ̻\׻1n dl?/#V?+]1/?8hgy7rf[q4]հ=fclӦ~M:n0W^?vinS* H@ p%  H@7؆?/[nh)=k_S`.BKQzVꑀ$  H4|8ͭt!$ :vQU[wOlQ/Y~>O{Tfvj|2ȹMGϽRW' H@>A! H@xiܳOty}elӎ[3;1~(ЮhFmؑk̇K1b⟣Y۟Vzl|&^/2lS<]$  H@om&z$  H@'o $  M:~->a BS7w$ϟ N XkS+&q=9_Xc%jdQ1W?jgzL?/:(_nTG^<\$  H@ p^ H@ ;_w};z@Zl%'nig1ojfvb\Q{NsuNMŎUtsj0?LlW4G=^Ӯl|6>Mo&9C/K@$P'@J H@i ʧY y4e?7;ooO;|sd6OG=^b6<M]f'j:vP|8ϝBȆ;mk`~:cks˙hsNM`g׫- H@I p$  H@Sٜ9&C^-~~ß̎Ox6)3MԦ6cFJ]vP|qTm1K#Sz?ƌY,̃1qy=&_~/q1[_v/v;a'& H@|>gh H@y;a $kgl>q3gLUl 3}ڌtY\qݎ-9=㚖md֠Z\G}N^g6[Yͬsy12hgsۏ=uz9oqy,Ԍ$ `suG௡mv;_贩y]|ʦgm슞6XQ;jRjsl!c׮46͍69Y~M\LS_ԫF5퀨= {H@$|x%  H@=z"^K@-`.h0&}? ve(QO֙}ΨWѭڜK#W;F7C=6LY^p?mε+6uB=1cF5"6F?s~lw"@0_TVsM0$  H@#3$  NՋY@On/lh>Gl,i:&:QC;g~FLGŎ\C73v-͖2eNl%hضg.ΉaLhXsqligsg?"7ksO5%  H@ؘ$  H`w6`5mpَ[ʎ'f0بǘLGEiK:ӎhZf*f{~5P_̛|3y>*X+kgs4[*6J;l˶>]O\♚c\M( H@> $  H@`'uB&@F#00?\l;Ҏڼf Gț\3 9yП#gO:hsNl!SsF^9͙/__;nTSuڜmΛ-?XϼƭP] T, H@q p{%  H@7p ft!]7~"?_|Ze n͜vׅ6L_ύ4Ԏv0oř~:e1sYdؼ>4Sc-Girf,ojd%kgskL[7uFc;g^mWtKi{P;jGm~ff.=ؽKlzsZ< %  H@'y_$  H`U}ub&κ- ^fG>α^юv?ǎ|s3kp,W5sXisNaO5-5i\P9qS5>3jg-C6 --*HCm>ҦvECTmꖲX;zms75?5aSO[j0?ovt7mk32zLel#Tt\R?o$  H@$oS$  %\?0oKO+>yF5mЦ65yzݴgv)=G?mjhSS;f=梟65agc+s㟪Y>rd:Y޾%1u]͟2?kfCO&?Kf3'?gBQ8/lKEH@$p.>~ H@@[%L"AJM5mЦf2\e?Tt 4׮ԣMMX㟺^*\9c u,<2uMc_ M%h3?isvfڜTK@$p>N9O H@ء]0?_TYiCf<튆̎#Aͨ=sjldqSl,FEC}K=Qojg)Mw2O&5Ϭ:?4sf[⍑$  H|8Ms$ ء&mƧMڙ&pRW+y4Sc-5g+T Ү䥆smͼӦ&l,3~^2W@?b2 M۟_:<ǹpLSG|7n=X}em?-螜&k?)V  H@9p*$  H@C¥?fEMPX?gξ^%W?R52?b/y]Wydy+LY;d~b3o%~Je~~^f۟6\{ kc^K@$pR>ƺ, H@86I`N۟-0>Ҏl@Ɔיŏz;AةzXl|69^˓f>G}לfL1S6 wm듀$  H|8MuI$ !%  H@'$wNxSZR;|ڼyS?eWrQ3ktyGmb,aOک̝<+{{Nh,1lM5[=ΜT堞6?S/~vbV׳$  H@''o˓$  \#p-][ϊ+>N꿀AL]ŧ͊&363ӻh-gzv6Ff355nj\3ksҏWq`sG,kTr-5墟s\-lΣZ/kU]gjy$  H|8 vy$ kpm $?*3>O-,~ڬAf-5y֦>9^*TJ梿3Z\Wjd+Lcj{bv-&;s8藀$  Hd|8 u9$ *Լ!?_/c, H@x >'ے52MQ=coQ{n~׮Yo*vjl*g?<N$  H@'&oK$  dC}EY-߂6H5GR֗dzelE%jm7\}gNؘGq} 5GfYloJJ$  HD|8t)$ *ԽE-~+hБYzhz]m1u-&㣹Z8Omҵ\7_L?üjPOzg>ul9}m΋y3-cJL#Xfdyz?yة):I@NJX% H@"p-]=?7fs{\+ԷG-Zj~꘧>V1zz未uVg{46r͉%~{֔igb^SgЖ$  <FL H@ ` F:X#\dg9v_ckyUVb{hQ=h*'E?Q sm/kϙ/}Fkgzh^;=c$  H@'oӗ$  B[# H@88px7UzK[b֚K%oE5|O3< yg.ytm/}^f|%zƺ, H@86I̞L 痕h)?fvsl9'{+3~T\k%>G?s6kpl*;o9n=6m棟65asvkKin0[,iW^S8wY :v $ "l* H@hh$<`bggcV^aڣ1cos1FEԍ`mYNjz{4>W&3+OkuҿݯͧzzOQ_?S$  '.I$"xJNw2yo1%֣yMb͜gr.Ϙ&vcFLG mMMzm{j}kn:gqzB_$  d( H@ t h'_׌3b+7)+DbQefFE]_rsr1OnhX/4kJ5c9^J ٣>O%59/+v_1s2zͱ7ig}v"$  H|8MuI$ t i;l7e6i~V޹jxM;kMSr9SszA?V4Znꛯ?gs ]ŌdY>vc{]h6νY;KMf?r2cM=m/SǮ]FE$  H|8 vy$ kFE_RyBQ;g\yi|s[jR*ycbsNQ1+/DpMddK@NL\& H@$(͜UR2}h1+d֛7Y楆~Ylhh9zSG}y*iX#FJ|v?Wu׮}J 5[f>z߷k]5\ŢS$pn>: H@Un\Ţ3#6Vf{+<1,&6˛5O\1նC?Xke1ԭkϜ+s:^3~ =_W41hsg-,WjTLY%3Oԣc4lfv7urJ$  H@'"nK$  T *ױ]E-a6Yo 62k̹f̞S9cY.M?6[ÎZ̻vkg6&31E?sm~QS/pMv&8( H@8'y_]$  H`;_+~9+DS>&o?{?NU+dyUcKS-6{af'#ǘs2_ѭq^G?A _;5kFm)Ry<ԛyyD,uͶ?=z%^$p>& H@(mN] d-J۟Y;,ǶR6M9Vͼ79_֠ }\='vO&Lۯi*jJ.*v_;gmg۟vy%  H@8(z㜶$  H`3V$pP~7no,&a Vّ0۳YfIyr̕٬ __ O룿Y1RC/UyrRyU9}9*[ڱ5x=wvjoʓ?7+$  H|8}t$ !n R)U7'lemHB]fWte{6c7 }iP\aΰ1|zzjskPٌg=3MglY|vk#9sDb͹;3G?wM;jS\&-ދv07$  였;9NM$;o`d5&y'~s B2heF:E3m 5Y;YVg]jX6916c2=5̩yy_b,NEiW8?ڡ36uH‘}nPʔ$  셀{C$!;olRKmFwQkaoEط1FmavL״ Me<},+s>ۮ6ޟ95y2X\z37͛yhvk,_U?Fmndmnu\|('T( H@ { %  H@`u&|L?? @GL6[f{6w>&⠞52;b\1;c3?ciGs6Xjz;kTYɕVUl*L<86fF̛ϬQ?"?+oN H@vH$ H@X[k~_d@Z +vԮz;r#8i3+~clSg΃L_Yh=c+ssb#W%>d uKY~MzUpKlNDm΅cWV>nLXyJ$  H`m>M$ p `7LS fk,8:kOQ;jWbzbzYLϜ36lΝsuzTڹOM3G ԇM]?6r=7h||TgF1~Fm^qN3|yGŏρŋP$ }`YH@6%/UQ h"-k\DfCx)Q?s3hugS6uS׬h|3M̋#YΨeLf3~߯f͜QEfobgHy$  H|8 vy$ kFE*+ϡBd2-쉖mߊc%>`qM\GV#Z8sAzY,55? jsb#O?m)y| Vkcz.C\D },% H@|ؚ$  H@; n£L[& 7[pcۍm`>ҏ&5Cklor~Ц6c1 ];b+ȗcV?sMcxxOMĆ\9e?UW4^8 H@f| $  H@!f>le7 |+*\>;wp=__2tl>YӦQDZYXk6F?iݴq5cLv[ڜ?bS^SبGXiG=^Wbͽzڟ"x}Xe^-g7$  H@$.o$  K]u+] ;/OslZaSW&y٪XyDvП m6n3)Sɕignz^13MR6_Iur=O9zUli'}151:+ H@|$  H@{ }ͪ? h:j3ϛ1Ҽvߪd,u~`̟Պcgl H@[xe" ->uSC]槆mN[לogl3g2_G Mg5zxֹf*fV%FhW4ǜx=jmRxM}iS3g±OөI@$$i. H@Ap(5g$m\>Ŏ3m2?5VjhxMk65ͯ׳ꨡ`l6CPG  V3ƧjcY9,v6cxGmz񙞭zG=lSCŎwN~<yw$  H`>l*$ ]p `W>_|;~!'WlOög/"G%XJ7[75lR9eǃϼ sf3{h3W_0g،ؼsx֦6[Ͷ}]iSQo޻$  H@X 4$  HH6x|o\rkl~ڙfj ҍMR99'Ʉ~p\sϼ?KM%6d:Y/i&l~ڌvUŰN mglfQ?Am\lggo%d<} :) H@'L( H@=v ˆ}g_m槦չvf<cGNsY|V[>^;dzS̨65as6ugvEOM{9+6[򙝵^6V?9E?q;WޯMY$ $7eH@F0BK$  H$In-Ͼ;>his6S<Ƙx}V#c2¦c*~rf`ɱQlƆQ?9LC}=ư֘cOa^G,r6uӮh2}ruYbg?Utp ˛ϞOu^:1M7-l1 H@G$  Hnz Aw]>Ҧva{KRv_mSV4G,Lغ6П\[q,W4SSc=blџY3MyC;Gm֠ͼlɏlGJ$`tK@L3ӵ= 퀏b; CfhxM]$`;o&i#&*|g,\rFmv0WL#~j_񧮳xi33 1+yM{3EͶ?1V?O{Tv}d]OI@$0- H@8$v-'- _dșO-Oi8Fm+?pbsM(쨝bL1oqŷ̦ 7IDATܳQ}g1g6%}L7XQY{?_D=fxy˷Fgzչ" H@*$ sXq E߁ڐ kYh뀿_Mk b36dYǘL5ifͱ-d4Sv0oy&~>rTbcG=lӮ+Ǽ{lF_?|xE( H@. p+ H@C`w!"NSNov@LmQ6)ߌ\ga,[#Kc+FDm֠劘vP|yJCV}ܵ}M֣M 5>nfN'jsO L"/\8&cjW* H@xp>< K@c`1 j &ןǖ%=3=gc||g+v_cx9JlfjWf.?_m3/Nؗ|>6 W/ H@x >|Y5oݐ$  gK$0A 8I@Jۈg]l0_wSArSnٌj:o_CYkv65zm%hVEGMfYfGll)ʾ?O_GK H@@3E  H@$n`r H5Mv@u$+XOާ]P_v{EdTmhWy15tKiZvK=mV*Ϙ96__6?kiWshg|/Jd$  H@!q3$  ,F-P "WKvN͖+[Fb4_a64GmЦ~ߎƟ:iD,|w>mviK$y,DﱅRF$ `wI@V L|b֒$?~P$jdd۟oRiSOŎ@vڙ&GJ<5#Q\k>ۛ?/ŖR[jpZcmv6F/""R\*y$  H@9v~$  H` ..;V 3cԩ+hg~~6߰Y>g>{hv%>t`󨟱SvCUli3kWbXmv6ƶPE[%  H@ vr#$  H`K nYZxH6ȶK mi~u9f>S3]i~3Mة1n6ן4=ڒ詉9f]ڧ?jzlGZI$ -. H@v3J@5'5_p=0̶?5E^Gm#ӌ#wú [aaΨ϶?lOO'Gx^EY $  H8|8νr$ XRI@oI;5퀯Ai3;Bgۘ[FͱvdQbX7>cimx^3's+cOuukc'g) H@X4$  H;ƌ$&Xpzl;xeα_Lfc?G=v<]igJlf۟-}sv}]$  H*b) H@87vνRW'!~8[7y?8g۟`+H>j-+km*zPO;v~f_6~٭tNZ/t.K$ 4%  H@B.S$@ܦ_[81F>?PO@1&R]E س}8F_p߿=$  H|8uY$ )nM&^5[cI͹ OmR"3&x%ާ>eCk~^k vb;'xs9;% H@Xk5$  H`nN$ =moA[a?*[ScO9/`=a.K DJ`M+ H@3|w$  H`%쬭T´M&k_Yʅ||{9. H@8!NxS]$  H)nY϶$.z-. !` H@q+$  !s [s=VR[ =5z"^K@LqT$pJ>( H@4!%H/ G {rlMz$ `7)H@&p=Zߠ$JxXe-'U$ STH@j|qR% H@8}`I~`I>|?~?׼Q9$  `b H@9/<: /p+agx{;3R$pX>9q H@#N rzGNp /M;#$  H|=p$ 9#tw9JmGJp {v$ H@ vs+$  H`;nlA+7eZ[ neb- H@޲$ {(nyHxq p;-{G;om H@p'𖕀$  ܓ[o;p+N-+8(_ h.Fb(M$ H@8s$  H`1_X&I0-乓v;a.Ac1$  ,JEqL$p >>9K H@6 Ipѻf'.I?{F;$  H`O|p.$ l39,99r nD-JZfadH@OCW  H@&0gi^n'D> r'Gwvvǜ$  H`>,$ 8Hl'}0מ ,:]vnk@$|x%  H@0>뺝J6n'7y_jPJ$p*>v H@@[5N n' 1 Np`kYf~, H@$  p{ Egnx oS$  M _$C `7e)5gvih_#LpKۿ_{#``owH@6 -! H@;q!o^Z[ s~j;5$  H`|}qV$ U *^oO[<0`h;GcW$h H@p;|%  H@ /.{"0=Ir5"``)摀$  YNU$"i}/턞g$O|W9w H@|a$ #p wϹv|sNA)n$  `j H@)p"G`B#VB#y)~)cw$ ;-) H@7}/U Jp acr ܑ;·$  H^|yJ@H-;·O`B[[ 1~mzv8* H@8%Ny[]$  H`WL;* H`BX.V H@@[uV*% SpxqvI@D3M" H@(p J$ glξЯ;|$  H@`Ȗ$  썀{#G$1 [BkXvf[u]$K>8) H@$  H@$  H@$  H@$  H@$  H@$  H@$  H@$  H@$  H@8- *IENDB`il329993 90 9,ˀƿ99%bƺ99!'ķ99r996ʺ96[®94{ij9-'ĵ9($ŵ9%#ŵ99#99|Ⱥ99`³959Ǻw91vż9-<ús9''Ws99#+5[u99/96Lzf9969983]wz\5097389 1=MSSN?29994$,489983+#$-4899960)!95.&984-$99`]]̀] ] ] !"! ]D !""#""! ]X !"#$#"! e]7 "##$##"!`] !"#$%$#"! ߀] Z ""#$$%$$##" ] ? "##$%$##" ] E ""#$$%$$#" ]E !"#$ %%$$##" ] E !"##$##"! q] M!""##$##"" g] \ !""#"! ]0 !!"! Ԃ]M ! ]+ ]3]'] >l] 2Ƀc]\^g@iZTMHB>;;IcڹvX@;G_}ϰqM;I[ťhH;TsƥcMit32"w{zs|#t&y+z.{ɀƀ |}πmҁtzׅy|هÿ|z܂݅¾|¼}¼u½½$/¾#)w¾"H $9ÿ&~¿$k"'Q|%v3k½SkĿt)|¼/vz!þh)u'{%ý'b{"&d¼&+t Ŀ&8{%<&~' f$&y!½%(!½}$g'þ#o%þ&Jm%ÿ~$)p$Ŀ}"s&|#r$ſz$r'ſy&r#ſw%q%ſw&q#ſv%q~(Ŀu&q}#þs'p{"r&pz"ſr(px!ýn&ox!|h'ov#ÿub(Cu#o(t{ÿh)kw½x'7tÿq*8o|p&]x|*StpU!n|ÿx#dy¾{R'Rqÿ|!l| ÿb*av|"$o} (Yvx@<8953N^RW^]`:894525LKLA692*++ Á t(++*89:15{{xȁ;2398>C5RKXF56689:-, =̗K-,:9 8,--*o$,/:975663ZYW8B;98963%y|-1:9@R ++*297R_049C_c\Z2579c^`+,,696M_^\-,:97R_^^;EB898W^w~~A0;T_^^Ѐ3a^^T^T^^T^^T^U^^_hhl8mkname icons8mkt8mk@mm3d-master/mm3d.reg000077500000000000000000000004521324021725400145520ustar00rootroot00000000000000Windows Registry Editor Version 5.00 [HKEY_CURRENT_USER\Software\Misfit Code\Misfit Model 3D] "INSTDIR"="C:\\Program Files\\Misfit Model 3D" mm3d-master/mm3dlogo.png000066400000000000000000000125001324021725400154340ustar00rootroot00000000000000PNG  IHDR=+= pHYs  d_IDATxO$IyƟȪ, 8'>XFy9 VlîWYq0KƂmY_X_^63;;S]CGѱoDV[mV[mV[fv۵feMjg¶W8yUM}S- oھv`!; ƍ{~<>;#HG38VhĶ g& )cB S[^^ BY 4ăq@h"PZR=}h;ӑ9b(ևЇp(525J5mdͦ@)S@@aϟ!r`>NWG^2J6P#J&~eY/2@5898g8'$`ox0.Qd0}(;zn+x=9A(̧'M/cPɺYP[6{py=p>〼(2"RđRj0A/59q(w= ̺ɨ"uA%G%C0cPJ:|Á$``m;b ̜*@RN  ![gc0ge0mNKa, ҦK6,~sq挠,K]˜rI^019s`Pv#^Mu#0g/xv}_YJ=Jjs@%ǯgv`w`]Oj?^ P."up[nMfc?yaVXxZCS/{(CP}c_s`5yʟt@#{N"'"䄙6S}+.-c%ޏ ٸ 5h-+nێKc\@2ʘ{d:v1hGXHV~ewu <(;0c]wmٍzC<|0J8tE(YQ<:2c  lO07W hI$5.HIu8Rzu?zK%OX^Jhp@*'YFc*WzDJ-s߫Id)\Jy z|Wd$a2;%AL)+W+]eU!8Ast=6!D-u6ҽҘIC}Cڶo컍ց ݨJy}ٶ "4JU4[gɰ5jɨ!<y: O]{Mh>Dl2>%$@b2I%̾TG 2ub"F%Y|*+o7uKSH7;++z@ dB9Z o TI~N-5I| x, KfGj>}=C /k>r YJx@"fx<@;vG#3%[*Kr|)g^%Y_L) M"˼&*}Qp9\G$7jaĀKZLsW'*0JjB-Z}(JG85mHV%% JSY5-QKCy 3GJ2lC$SIY)K[sJLX&Kf-ne%8&%30=?Z>~hPV%c0j L],h2j; \;dʶr4=ܞJĕҿD)h@qsJ:ԳL$TwN)_:,>hx ǒ ^ת'>7R̰Kw1W %]bζKKC *1`JQ˧#>i(O#OĮ@’PX9" +oQ)Oo=m͜Bl4QsP2REr&cukcK@'s/>Y(ǽN@ǶʺKjFM_4jBhNJ)o3 [u>5Ke᳀Yͼ9T*Z H|&b=_wpSg="tR 5 U&N-M{RNR)ؙ%KC,GbP!m8HNJ?NPxMfjڻ&)l Tc9R&Γ]TfrP[;}K0vP6meU\ Cĕ}$GF5' 8~s֭}]z BUYrkuj`$%(fn&մ;%dl?RȚl~౰Z"Ӿ6Ča(&'RI8&UkZ5-J_RM(@2!XJ6HP\xg%Sα=o >ecK=03d_61bR-"@;~bɾK i_uܕJ#Pz)ѱsTʔbhO{s攒롔2ws*u)ei\Yڏ5i#1Cnl24e-g]Ҏ 6/-K2[l}9dm KRˌHCLg^Mƭ cRJ bJ7T֞S<6B%Ɣ%j)}62t sɖSWQe FMf_J2'S²õc`JkR6~0꘻;ŖRIqdL)6dARL,ȨUĒlTK(iȭS@JcWn#7*jl vL]Ӓjč:!ۄRȾ T06aKEl%-XK w^ ڎA)Q8',2Sg+y)5}wO2@n#*9r+%U|?rVXz,F)%iq{ns-{pjJA,C+k!d쒜ɖ,|QʖLwbW%_c5k-}>mब{J FbP!M[ȠsP5sY6iV n6[(劵!\DV#-åB4윁Y2a\f+(?FIOma-\[ªS\Oʾo}i?b@,<%7 T*8Ijy#B8XzlBP\I1}TAmkA*lR-S_ 8}\]K6 I@-=rS&~UbP>7ŝ3)Ĕ"Y gc1v"?gZe*6%欔Zl('xZTAo?dAQ[[LO%3-t#|ln޷ܩ;UlYxZs.g>C4UiQ |B);u=nO6򚯒M>RKfHA\[d{fJnkD}oWF gPnH<$VW攕Qpndy5J>_^Y5BZ- ىIDDt1*6P_;,9lK\b[E5UL9}&u+np1F%SX̾d=TfNP3=wenmw6ȍbP˒/Z>͖x]nl2P|M17֬%;+pr&gS qQVIV};BX>TO|Z\) k0mJP> |;Bcv.N!bJ6 ,9 xr+k @V(-p]N#@. ;(&IEb}=kq@(oba5v Ԫ%U<څv dF8VE9i?rBTQKNƐl4}!>quj߉;)#0ߎG- ?X՘f붋 ܝ tyA*)hp9F-MFjŎ/0ޮP̝:|Qic*טec#7*~{ϪXԝ9< -~~#y6bu#B9P2ԵaUD5ddLz?~T('^t'wz Hdj1(jѩfV3oaP2j>A`\US~)Tџ剩@{_}4vB0nE^՘r *c'GWe=И [U]e߷g_ dߦ void segfault_handler( int sig ) { fprintf( stderr, "Segfault. Exiting...\n" ); exit( 0 ); } int free_memory() { return model_free_primitives(); } int main( int argc, char * argv[] ) { int rval = 0; log_profile_init( "profile_data.txt" ); signal( SIGSEGV, segfault_handler ); init_sysconf(); transimp_install_translator(); init_prefs(); init_cmdline( argc, argv ); ui_prep( argc, argv ); { LOG_PROFILE(); { LOG_PROFILE_STR( "Initialize" ); // set up keyboard shortcuts std::string keycfgFile = getMm3dHomeDirectory(); keycfgFile += "/keycfg.in"; keycfg_load_file( keycfgFile.c_str() ); keycfg_set_defaults(); init_std_filters(); init_std_texture_filters(); init_std_tools(); init_std_cmds( CommandManager::getInstance() ); init_plugins(); model_status_register_function( StatusBar::getStatusBarFromModel ); } rval = ui_init( argc, argv ); { LOG_PROFILE_STR( "Uninitialize" ); std::string keycfgFile = getMm3dHomeDirectory(); keycfgFile += "/keycfg.out"; keycfg_save_file( keycfgFile.c_str() ); shutdown_cmdline(); model_show_alloc_stats(); DecalManager::release(); CommandManager::release(); FilterManager::release(); TextureManager::release(); PluginManager::release(); free_memory(); model_show_alloc_stats(); show_alloc_stats(); prefs_save(); } } log_profile_shutdown(); return rval; } mm3d-master/src/Makefile.am000066400000000000000000000017241324021725400160360ustar00rootroot00000000000000SUBDIRS = libmm3d mm3dcore depui qtui implui tools commands pixmap bin_PROGRAMS = mm3d EXTRA_DIST = icon.rc maketags.sh mm3d_HFILES = \ stdcmds.h \ stdfilters.h \ stdtexfilters.h \ stdtools.h mm3d_SOURCES = \ 3dm.cc \ stdcmds.cc \ stdfilters.cc \ stdtexfilters.cc \ stdtools.cc \ $(mm3d_HFILES) mm3d_LDADD = $(CORE_PROFILE) tools/libtools.a commands/libcommands.a implui/libimplui.a qtui/libqtui.a depui/libdepui.a mm3dcore/libmm3dcore.a libmm3d/libmm3d.a $(QGL_LIBS) $(QT_LIBS) $(LUALIB_LIBS) $(GL_LIBS) $(DLOPEN_LIBS) $(COVLFLAGS) mm3d_LDFLAGS = $(all_libraries) $(QT_CXXFLAGS) AM_CPPFLAGS = $(CORE_PROFILE) $(COVFLAGS) -Wall -Ilibmm3d -Imm3dcore -Idepui -Iqtui -Iimplui -Itools -Icommands -DMM3D_EDIT $(all_includes) $(QT_CXXFLAGS) $(LUALIB_CCFLAGS) $(GL_CFLAGS) %.moc.cc: %.h $(QT_MOC) -o $@ $< wc: wc `ls *.h *.cpp *.cc *.y *.l */*.h */*.cpp */*.cc */*.y */*.l 2> /dev/null | grep -v moc.cc | grep -v "\.base\." ` | sort -n CLEANFILES = *.gcno *.gcda mm3d-master/src/commands/000077500000000000000000000000001324021725400155775ustar00rootroot00000000000000mm3d-master/src/commands/Makefile.am000066400000000000000000000023051324021725400176330ustar00rootroot00000000000000noinst_LIBRARIES = libcommands.a libcommands_HFILES = \ aligncmd.h \ assignjointcmd.h \ backgroundcmd.h \ capcmd.h \ copycmd.h \ deletecmd.h \ dupcmd.h \ edgedivcmd.h \ edgeturncmd.h \ extrudecmd.h \ faceoutcmd.h \ flattencmd.h \ flipcmd.h \ hidecmd.h \ invertcmd.h \ invnormalcmd.h \ jointcmd.h \ makefacecmd.h \ pastecmd.h \ pointcmd.h \ rotatetexcmd.h \ selectfreecmd.h \ simplifycmd.h \ snapcmd.h \ spherifycmd.h \ subdividecmd.h \ unweldcmd.h \ weldcmd.h libcommands_a_SOURCES = \ aligncmd.cc \ assignjointcmd.cc \ backgroundcmd.cc \ capcmd.cc \ copycmd.cc \ deletecmd.cc \ dupcmd.cc \ edgedivcmd.cc \ edgeturncmd.cc \ extrudecmd.cc \ faceoutcmd.cc \ flattencmd.cc \ flipcmd.cc \ hidecmd.cc \ invertcmd.cc \ invnormalcmd.cc \ jointcmd.cc \ makefacecmd.cc \ pastecmd.cc \ pointcmd.cc \ rotatetexcmd.cc \ selectfreecmd.cc \ simplifycmd.cc \ snapcmd.cc \ spherifycmd.cc \ subdividecmd.cc \ unweldcmd.cc \ weldcmd.cc \ $(libcommands_HFILES) AM_CPPFLAGS = $(CORE_PROFILE) $(COVFLAGS) -Wall -I../libmm3d -I../mm3dcore -I../depui -I../qtui -I../implui -I../ -DMM3D_EDIT $(all_includes) $(QT_CXXFLAGS) $(LUALIB_CCFLAGS) $(GL_CFLAGS) CLEANFILES = *.gcno *.gcda mm3d-master/src/commands/aligncmd.cc000066400000000000000000000026061324021725400176700ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "aligncmd.h" #include "alignwin.h" #include "align.h" #include "log.h" #include #include AlignCommand::AlignCommand() { } AlignCommand::~AlignCommand() { } bool AlignCommand::activated( int arg, Model * model ) { AlignWin * win = new AlignWin( model ); win->show(); return true; } const char * AlignCommand::getPath() { return GEOM_MESHES_MENU; } const char * AlignCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Align Selected..." ); } mm3d-master/src/commands/aligncmd.h000066400000000000000000000025421324021725400175310ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ALIGNCMD_H #define __ALIGNCMD_H #include "command.h" #include class AlignCommand : public Command { public: AlignCommand(); virtual ~AlignCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool isPrimitive() { return true; }; protected: }; #endif // __ALIGNCMD_H mm3d-master/src/commands/assignjointcmd.cc000066400000000000000000000052301324021725400211220ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "assignjointcmd.h" #include "jointwin.h" #include "model.h" #include "modelstatus.h" #include "log.h" #include #include #include AssignJointCommand::AssignJointCommand() { } AssignJointCommand::~AssignJointCommand() { } bool AssignJointCommand::activated( int arg, Model * model ) { std::list j; model->getSelectedBoneJoints( j ); if ( j.size() == 1 ) { unsigned int joint = j.front(); list::iterator it; list vertList; model->getSelectedVertices( vertList ); list pointList; model->getSelectedPoints( pointList ); log_debug( "assigning %d vertices and %d points to joint %d\n", vertList.size(), pointList.size(), joint ); QString str = qApp->translate( "Command", "Assigning %1 vertices and %2 points to joint %3" ); str = str .arg(vertList.size()) .arg(pointList.size()) .arg(joint); model_status( model, StatusNormal, STATUSTIME_SHORT, "%s", (const char *) str.toUtf8() ); for ( it = vertList.begin(); it != vertList.end(); it++ ) { model->setVertexBoneJoint( *it, joint ); } for ( it = pointList.begin(); it != pointList.end(); it++ ) { model->setPointBoneJoint( *it, joint ); } } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have exactly 1 bone joint selected." ).toUtf8() ); JointWin * win = new JointWin( model ); win->show(); } return true; } bool AssignJointCommand::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::CTRL + Qt::Key_B; return true; } const char * AssignJointCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Assign Selected to Bone Joint" ); } mm3d-master/src/commands/assignjointcmd.h000066400000000000000000000025271324021725400207720ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ASSIGNJOINTCMD_H #define __ASSIGNJOINTCMD_H #include "command.h" #include class AssignJointCommand : public Command { public: AssignJointCommand(); virtual ~AssignJointCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ); bool isPrimitive() { return true; }; protected: }; #endif // __ASSIGNJOINTCMD_H mm3d-master/src/commands/backgroundcmd.cc000066400000000000000000000025161324021725400207150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "backgroundcmd.h" #include "backgroundwin.h" #include "log.h" #include #include BackgroundCommand::BackgroundCommand() { } BackgroundCommand::~BackgroundCommand() { } bool BackgroundCommand::activated( int arg, Model * model ) { BackgroundWin * win = new BackgroundWin( model ); win->show(); return true; } const char * BackgroundCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Set Background Image..." ); } mm3d-master/src/commands/backgroundcmd.h000066400000000000000000000025421324021725400205560ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BACKGROUNDCMD_H #define __BACKGROUNDCMD_H #include "command.h" #include class BackgroundCommand : public Command { public: BackgroundCommand(); virtual ~BackgroundCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool isPrimitive() { return true; }; protected: }; #endif // __BACKGROUNDCMD_H mm3d-master/src/commands/capcmd.cc000066400000000000000000000170761324021725400173500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "capcmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include CapCommand::CapCommand() { } CapCommand::~CapCommand() { } bool CapCommand::activated( int arg, Model * model ) { int added = 0; // Algorithm: // // Selected edges // For each selected vertex, check every vertex connected to it // // For each connected edge that does not belong to two triangles, // add a triangle using a third vertex from another triangle // that uses this vertex and another selected vertex list vertList; list triList; // triangles using target vertex list conList; // vertices connected to target vertex model->getSelectedVertices( vertList ); std::list::iterator it; for ( it = vertList.begin(); it != vertList.end(); it++ ) { getConnected( model, *it, conList, triList ); unsigned int vcount = conList.size(); unsigned int tcount = triList.size(); if ( vcount > 2 && vcount != tcount ) { // If I'm connected to more than two vertices, the // triangle and vertex count should match, otherwise // there is a gap/hole. int newTri = 0; while ( tcount != vcount && newTri >= 0 ) { newTri = createMissingTriangle( model, *it, conList, triList ); if ( newTri >= 0 ) { added++; tcount++; triList.push_back( newTri ); } } } } if ( added != 0 ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Cap Holes complete").toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Could not find gap in selected region" ).toUtf8() ); } return false; } void CapCommand::getConnected( Model * model, int v, std::list & conList, std::list & triList ) { conList.clear(); triList.clear(); unsigned int tcount = model->getTriangleCount(); for ( unsigned int tri = 0; tri < tcount; tri++ ) { unsigned int verts[3]; model->getTriangleVertices( tri, verts[0], verts[1], verts[2] ); for ( int i = 0; i < 3; i++ ) { if ( (int) verts[i] == v ) { triList.push_back( tri ); addToList( conList, v, verts[0] ); addToList( conList, v, verts[1] ); addToList( conList, v, verts[2] ); break; } } } } void CapCommand::addToList( std::list & l, int ignore, int val ) { if ( ignore == val ) { return; } std::list::iterator it; for ( it = l.begin(); it != l.end(); it++ ) { if ( *it == val ) { return; } } l.push_back( val ); } int CapCommand::createMissingTriangle( Model * model, unsigned int v, std::list & conList, std::list & triList ) { std::list::iterator cit1; std::list::iterator cit2; int tri = 0; for ( cit1 = conList.begin(); cit1 != conList.end(); cit1++ ) { if ( model->isVertexSelected( *cit1 ) ) { if ( triangleCount( model, v, *cit1, triList, tri ) == 1 ) { cit2 = cit1; cit2++; // Find third triangle vertex for normal test below int tri1Vert = 0; unsigned int verts[3]; model->getTriangleVertices( tri, verts[0], verts[1], verts[2] ); for ( int i = 0; i < 3; i++ ) { if ( verts[i] != v && verts[i] != (unsigned int) *cit1 ) { tri1Vert = verts[i]; } } for ( ; cit2 != conList.end(); cit2++ ) { if ( model->isVertexSelected( *cit2 ) ) { if ( triangleCount( model, v, *cit2, triList, tri ) == 1 ) { int newTri = model->addTriangle( v, *cit1, *cit2 ); float norm1[3]; float norm2[3]; double coord[3]; model->getFlatNormal( tri, norm1 ); model->getFlatNormal( newTri, norm2 ); model->getVertexCoords( *cit1, coord ); // this is why we needed the third vertex above, // so we can check to see if we need to invert // the new triangle (are the triangles behind // each other or in front of each other?) float f = model->cosToPoint( tri, coord ); if ( fabs( f ) < 0.0001f ) { // Points are nearly co-planar, // normals should face the same way if ( dot3( norm1, norm2 ) < 0.0f ) { model->invertNormals( newTri ); } } else { if ( f < 0.0f ) { model->getVertexCoords( tri1Vert, coord ); if ( model->cosToPoint( newTri, coord ) > 0.0f ) { model->invertNormals( newTri ); } } else { model->getVertexCoords( tri1Vert, coord ); if ( model->cosToPoint( newTri, coord ) < 0.0f ) { model->invertNormals( newTri ); } } } return newTri; } } } } } } return -1; } int CapCommand::triangleCount( Model * model, unsigned int v1, unsigned int v2, std::list & triList, int & tri ) { std::list::iterator it; unsigned int verts[3]; int triCount = 0; for ( it = triList.begin(); it != triList.end(); it++ ) { model->getTriangleVertices( *it, verts[0], verts[1], verts[2] ); bool have1 = false; bool have2 = false; for ( int i = 0; i < 3; i++ ) { if ( verts[i] == v1 ) have1 = true; else if ( verts[i] == v2 ) have2 = true; } if ( have1 && have2 ) { triCount++; tri = *it; } } return triCount; } const char * CapCommand::getPath() { return GEOM_MESHES_MENU; } const char * CapCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Cap Holes" ); } mm3d-master/src/commands/capcmd.h000066400000000000000000000033311324021725400171770ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CAPCMD_H #define __CAPCMD_H #include "command.h" #include class CapCommand : public Command { public: CapCommand(); virtual ~CapCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: void getConnected( Model * model, int vert, std::list & conList, std::list & triList); void addToList( std::list & l, int ignore, int val ); int createMissingTriangle( Model * model, unsigned int v, std::list & conList, std::list & triList ); int triangleCount( Model * model, unsigned int v1, unsigned int v2, std::list & triList, int & tri ); }; #endif // __CAPCMD_H mm3d-master/src/commands/copycmd.cc000066400000000000000000000043521324021725400175500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "copycmd.h" #include "model.h" #include "filtermgr.h" #include "texmgr.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include "sysconf.h" #include "misc.h" #include #include #include #include using std::list; using std::map; CopyCommand::CopyCommand() { } CopyCommand::~CopyCommand() { } bool CopyCommand::activated( int arg, Model * model ) { if ( !model ) return false; if ( model->getSelectedTriangleCount() == 0 && model->getSelectedPointCount() == 0 && model->getSelectedProjectionCount() == 0 ) { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have at least 1 face, joint, or point selected to Copy" ).toUtf8() ); return false; } Model * m = model->copySelected(); if ( !m ) return false; model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selected primitives copied" ).toUtf8() ); std::string clipfile = getMm3dHomeDirectory(); clipfile += "/clipboard"; mkpath( clipfile.c_str(), 0755 ); clipfile += "/clipboard.mm3d"; FilterManager::getInstance()->writeFile( m, clipfile.c_str(), FilterManager::WO_ModelNoPrompt ); delete m; return true; } const char * CopyCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Copy Selected to Clipboard" ); } mm3d-master/src/commands/copycmd.h000066400000000000000000000025361324021725400174140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __COPYCMD_H #define __COPYCMD_H #include "command.h" #include class CopyCommand : public Command { public: CopyCommand(); virtual ~CopyCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::CTRL+Qt::Key_C; return true; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __COPYCMD_H mm3d-master/src/commands/deletecmd.cc000066400000000000000000000046661324021725400200500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include #include #include #include "deletecmd.h" #include "model.h" #include "msg.h" #include "modelstatus.h" DeleteCommand::DeleteCommand() { } DeleteCommand::~DeleteCommand() { } const char * DeleteCommand::getName( int arg ) { if ( arg == 0 ) { return QT_TRANSLATE_NOOP( "Command", "Delete" ); } else { return "[Out of range]"; } } bool DeleteCommand::getKeyBinding( int arg, int & keyBinding ) { if ( arg == 0 ) { keyBinding = Qt::Key_Delete; return true; } else { return false; } } bool DeleteCommand::activated( int arg, Model * model ) { if ( arg == 0 && model ) { static bool warnedAlready = false; std::list joints; model->getSelectedBoneJoints( joints ); bool doDelete = true; if ( model->getAnimationMode() == Model::ANIMMODE_NONE && joints.size() > 0 && model->getAnimCount( Model::ANIMMODE_SKELETAL ) > 0 && !warnedAlready ) { QString s = qApp->translate( "Command", "Deleting joints may destroy skeletal animations\nDo you wish to continue?" ); if ( msg_warning_prompt( (const char *) s.toUtf8(), "yN" ) == 'Y' ) { warnedAlready = true; } else { doDelete = false; } } if ( doDelete ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Primitives deleted" ).toUtf8() ); model->deleteSelected(); } return doDelete; } else { return false; } } mm3d-master/src/commands/deletecmd.h000066400000000000000000000024111324021725400176740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __DELETECMD_H #define __DELETECMD_H #include "command.h" class DeleteCommand : public Command { public: DeleteCommand(); virtual ~DeleteCommand(); int getCommandCount() { return 1; }; bool getKeyBinding( int arg, int & keyBinding ); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __DELETECMD_H mm3d-master/src/commands/dupcmd.cc000066400000000000000000000164421324021725400173710ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "dupcmd.h" #include "model.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include #include #include #include using std::list; using std::map; DuplicateCommand::DuplicateCommand() { } DuplicateCommand::~DuplicateCommand() { } bool DuplicateCommand::activated( int arg, Model * model ) { if ( model ) { list tri; model->getSelectedTriangles( tri ); list joints; model->getSelectedBoneJoints( joints ); list points; model->getSelectedPoints( points ); list vert; map vertMap; map triMap; map jointMap; map pointMap; list::iterator lit; if ( !tri.empty() ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selected primitives duplicated" ).toUtf8() ); model->getSelectedVertices( vert ); // Duplicated vertices log_debug( "Duplicating %d vertices\n", vert.size() ); for ( lit = vert.begin(); lit != vert.end(); lit++ ) { double coords[3]; model->getVertexCoords( *lit, coords ); int nv = model->addVertex( coords[0], coords[1], coords[2] ); if ( model->isVertexFree( *lit ) ) { model->setVertexFree( nv, true ); } vertMap[ *lit ] = nv; } // Duplicate faces log_debug( "Duplicating %d faces\n", tri.size() ); for ( lit = tri.begin(); lit != tri.end(); lit++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = model->getTriangleVertex( *lit, t ); } int nt = model->addTriangle( vertMap[v[0]] , vertMap[v[1]], vertMap[v[2]] ); triMap[ *lit ] = nt; } // Duplicate texture coords log_debug( "Duplicating %d face texture coordinates\n", tri.size() ); for ( lit = tri.begin(); lit != tri.end(); lit++ ) { float s; float t; for ( unsigned i = 0; i < 3; i++ ) { model->getTextureCoords( (unsigned) *lit, i, s, t ); model->setTextureCoords( (unsigned) triMap[ *lit ], i, s, t ); } } if ( model->getGroupCount() ) { // Set groups log_debug( "Setting %d triangle groups\n", tri.size() ); for ( lit = tri.begin(); lit != tri.end(); lit++ ) { // This works, even if triangle group == -1 int gid = model->getTriangleGroup(*lit); if ( gid >= 0 ) { model->addTriangleToGroup( gid, triMap[*lit] ); } } } } if ( !joints.empty() ) { // Duplicated joints log_debug( "Duplicating %d joints\n", joints.size() ); for ( lit = joints.begin(); lit != joints.end(); lit++ ) { int parent = model->getBoneJointParent( *lit ); // TODO this will not work if parent joint comes after child // joint. That shouldn't happen... but... if ( model->isBoneJointSelected( parent ) ) { parent = jointMap[ parent ]; } // If joint is root joint, assign duplicated joint to be child // of original if ( parent == -1 ) { parent = 0; } double coord[3]; double rot[3] = { 0, 0, 0 }; model->getBoneJointCoords( *lit, coord ); int nj = model->addBoneJoint( model->getBoneJointName( *lit ), coord[0], coord[1], coord[2], rot[0], rot[1], rot[2], parent ); jointMap[ *lit ] = nj; // Assign duplicated vertices to duplicated bone joints list vertlist = model->getBoneJointVertices( *lit ); list::iterator vit; for ( vit = vertlist.begin(); vit != vertlist.end(); vit++ ) { if ( model->isVertexSelected( *vit ) ) { model->setVertexBoneJoint( vertMap[ *vit ], nj ); } } } } if ( !points.empty() ) { // Duplicated points log_debug( "Duplicating %d points\n", points.size() ); for ( lit = points.begin(); lit != points.end(); lit++ ) { int parent = model->getPointBoneJoint( *lit ); if ( model->isBoneJointSelected( parent ) ) { parent = jointMap[ parent ]; } double coord[3]; double rot[3] = { 0, 0, 0 }; model->getPointCoords( *lit, coord ); model->getPointRotation( *lit, rot ); int np = model->addPoint( model->getPointName( *lit ), coord[0], coord[1], coord[2], rot[0], rot[1], rot[2], parent ); pointMap[ *lit ] = np; } } model->unselectAll(); // Select vertices log_debug( "reselecting vertices\n" ); for ( lit = vert.begin(); lit != vert.end(); lit++ ) { model->selectVertex( vertMap[*lit] ); } // Select faces log_debug( "reselecting faces\n" ); for ( lit = tri.begin(); lit != tri.end(); lit++ ) { model->selectTriangle( triMap[*lit] ); } // Select bone joints log_debug( "reselecting bone joints\n" ); for ( lit = joints.begin(); lit != joints.end(); lit++ ) { model->selectBoneJoint( jointMap[*lit] ); } // Select points log_debug( "reselecting points\n" ); for ( lit = points.begin(); lit != points.end(); lit++ ) { model->selectPoint( pointMap[*lit] ); } model->invalidateNormals(); if ( joints.empty() && tri.empty() && points.empty() ) { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have at least 1 face, joint, or point selected to Duplicate" ).toUtf8() ); return false; } else { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Duplicate complete" ).toUtf8() ); } return true; } else { return false; } } const char * DuplicateCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Duplicate" ); } mm3d-master/src/commands/dupcmd.h000066400000000000000000000025521324021725400172300ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __DUPCMD_H #define __DUPCMD_H #include "command.h" #include class DuplicateCommand : public Command { public: DuplicateCommand(); virtual ~DuplicateCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::CTRL+Qt::Key_D; return true; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __DUPCMD_H mm3d-master/src/commands/edgedivcmd.cc000066400000000000000000000074111324021725400202040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "edgedivcmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include EdgeDivideCommand::EdgeDivideCommand() { } EdgeDivideCommand::~EdgeDivideCommand() { } bool EdgeDivideCommand::activated( int arg, Model * model ) { int split = 0; list vertList; model->getSelectedVertices( vertList ); if ( vertList.size() >= 2 ) { // Only divides one edge, deal with it unsigned int v1 = vertList.front(); vertList.pop_front(); unsigned int v2 = vertList.front(); double coord1[3]; double coord2[3]; model->getVertexCoords( v1, coord1 ); model->getVertexCoords( v2, coord2 ); for ( int i = 0; i < 3; i++ ) { coord1[i] = (coord1[i] + coord2[i]) / 2.0; } unsigned int v3 = model->addVertex( coord1[0], coord1[1], coord1[2] ); // The triangle count will grow while we're iterating, but that's okay // because we know that the new triangles don't need to be split unsigned int tcount = model->getTriangleCount(); for ( unsigned int tri = 0; tri < tcount; tri++ ) { const int INVALID = ~0; int a = INVALID; int b = INVALID; int c = INVALID; unsigned int tv[3] = {0,0,0}; model->getTriangleVertices( tri, tv[0], tv[1], tv[2] ); for ( int i = 0; i < 3; i++ ) { if ( tv[i] == v1 ) a = i; else if ( tv[i] == v2 ) b = i; else c = i; } // don't assume 'c' is set, triangle may have one vertex // assigned to two corners if ( a != INVALID && b != INVALID && c != INVALID ) { int g = model->getTriangleGroup( tri ); int vert[3]; vert[ a ] = v3; vert[ b ] = tv[b]; vert[ c ] = tv[c]; int newTri = model->addTriangle( vert[0], vert[1], vert[2] ); if ( g >= 0 ) { model->addTriangleToGroup( newTri, g ); } vert[ a ] = tv[a]; vert[ b ] = v3; vert[ c ] = tv[c]; model->setTriangleVertices( tri, vert[0], vert[1], vert[2] ); split++; } } model->unselectAllVertices(); model->selectVertex( v3 ); } if ( split > 0 ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Edge Divide complete" ).toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have at 2 adjacent vertices to Edge Divide" ).toUtf8() ); } return false; } const char * EdgeDivideCommand::getPath() { return GEOM_FACES_MENU; } const char * EdgeDivideCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Edge Divide" ); } mm3d-master/src/commands/edgedivcmd.h000066400000000000000000000024161324021725400200460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __EDGEDIVCMD_H #define __EDGEDIVCMD_H #include "command.h" class EdgeDivideCommand : public Command { public: EdgeDivideCommand(); virtual ~EdgeDivideCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __EDGEDIVCMD_H mm3d-master/src/commands/edgeturncmd.cc000066400000000000000000000137271324021725400204210ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "edgeturncmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include EdgeTurnCommand::EdgeTurnCommand() { } EdgeTurnCommand::~EdgeTurnCommand() { } bool EdgeTurnCommand::activated( int arg, Model * model ) { list triList; model->getSelectedTriangles( triList ); if ( triList.size() >= 2 ) { // Only turns one edge, deal with it unsigned int edge_v1; unsigned int edge_v2; unsigned int tri1_v; unsigned int tri2_v; list::iterator it1 = triList.begin(); list::iterator it2 = it1; for ( it1 = triList.begin(); it1 != triList.end(); it1++ ) { it2 = it1; it2++; for ( ; it2 != triList.end(); it2++ ) { if ( canTurnEdge( model, *it1, *it2, edge_v1, edge_v2, tri1_v, tri2_v ) ) { log_debug( "turning edge on triangles %d and %d\n", *it1, *it2 ); log_debug( "vertices %d,%d,%d %d,%d,%d\n", edge_v1, edge_v2, tri1_v, edge_v1, edge_v2, tri2_v ); int t1a = 0; int t1b = 0; int t1c = 0; int t2a = 0; int t2b = 0; int t2c = 0; getTriangleVertices( model, *it1, edge_v1, edge_v2, tri1_v, t1a, t1b, t1c ); getTriangleVertices( model, *it2, edge_v1, edge_v2, tri2_v, t2a, t2b, t2c ); log_debug( "indices %d,%d,%d %d,%d,%d\n", t1a, t1b, t1c, t2a, t2b, t2c ); // For triangle 1: unsigned int verts1[ 3 ]; unsigned int verts2[3]; verts1[ t1a ] = tri1_v; verts1[ t1b ] = tri2_v; verts1[ t1c ] = edge_v2; verts2[ t2a ] = tri1_v; verts2[ t2b ] = tri2_v; verts2[ t2c ] = edge_v1; model->setTriangleVertices( *it1, verts1[0], verts1[1], verts1[2] ); model->setTriangleVertices( *it2, verts2[0], verts2[1], verts2[2] ); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Edge Turn complete" ).toUtf8() ); return true; } } } } model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have at least 2 adjacent faces to Edge Turn" ).toUtf8() ); return false; } // edge_v1 and edge_v2 are the model vertices of the common edge // tri1_v and tri2_v are the opposite vertices of the respective triangles bool EdgeTurnCommand::canTurnEdge( Model * model, int tri1, int tri2, unsigned int & edge_v1, unsigned int & edge_v2, unsigned int & tri1_v, unsigned int & tri2_v ) { unsigned int verts1[3]; unsigned int verts2[3]; model->getTriangleVertices( tri1, verts1[0], verts1[1], verts1[2] ); model->getTriangleVertices( tri2, verts2[0], verts2[1], verts2[2] ); const unsigned int invalid = (unsigned) ~0; edge_v1 = invalid; edge_v2 = invalid; tri1_v = invalid; tri2_v = invalid; for ( int i1 = 0; i1 < 3; i1++ ) { unsigned int v1 = verts1[i1]; if ( v1 != edge_v1 && v1 != edge_v2 ) { for ( int i2 = 0; i2 < 3; i2++ ) { unsigned int v2 = verts2[i2]; if ( v2 != edge_v1 && v2 != edge_v2 ) { if ( v1 == v2 ) { if ( edge_v1 == invalid ) edge_v1 = v1; else if ( edge_v2 == invalid ) edge_v2 = v1; } } } } } if ( edge_v1 != invalid && edge_v2 != invalid ) { int i; for ( i = 0; i < 3; i++ ) { if ( verts1[i] != edge_v1 && verts1[i] != edge_v2 ) { tri1_v = verts1[i]; break; } } for ( i = 0; i < 3; i++ ) { if ( verts2[i] != edge_v1 && verts2[i] != edge_v2 ) { tri2_v = verts2[i]; break; } } return true; } else { return false; } } // Triangle index a is edge_v1 // Triangle index b is edge_v2 // Triangle index c is tri_v, the third triangle vertex // // Note that a, b, and c are the indices into the list of three triangle vertices, // not the index of the model vertices void EdgeTurnCommand::getTriangleVertices( Model * model, int tri, unsigned int edge_v1, unsigned int edge_v2, unsigned int tri_v, int & a, int & b, int & c ) { unsigned int v[3] = {0,0,0}; model->getTriangleVertices( tri, v[0], v[1], v[2] ); for ( int i = 0; i < 3; i++ ) { if ( v[i] == edge_v1 ) a = i; else if ( v[i] == edge_v2 ) b = i; else if ( v[i] == tri_v ) c = i; } } const char * EdgeTurnCommand::getPath() { return GEOM_FACES_MENU; } const char * EdgeTurnCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Edge Turn" ); } mm3d-master/src/commands/edgeturncmd.h000066400000000000000000000031371324021725400202550ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __EDGETURNCMD_H #define __EDGETURNCMD_H #include "command.h" class EdgeTurnCommand : public Command { public: EdgeTurnCommand(); virtual ~EdgeTurnCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: bool canTurnEdge( Model * model, int tri1, int tri2, unsigned int & edge_v1, unsigned int & edge_v2, unsigned int & tri1_v, unsigned int & tri2_v ); void getTriangleVertices( Model * model, int tri, unsigned int edge_v1, unsigned int edge_v2, unsigned int tri_v, int & a, int & b, int & c ); }; #endif // __EDGETURNCMD_H mm3d-master/src/commands/extrudecmd.cc000066400000000000000000000024621324021725400202560ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "extrudecmd.h" #include "extrudewin.h" #include "log.h" #include #include ExtrudeCommand::ExtrudeCommand() { } ExtrudeCommand::~ExtrudeCommand() { } bool ExtrudeCommand::activated( int arg, Model * model ) { ExtrudeWin * win = new ExtrudeWin( model ); win->exec(); delete win; return true; } const char * ExtrudeCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Extrude..." ); } mm3d-master/src/commands/extrudecmd.h000066400000000000000000000025541324021725400201220ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __EXTRUDECMD_H #define __EXTRUDECMD_H #include "command.h" #include class ExtrudeCommand : public Command { public: ExtrudeCommand(); virtual ~ExtrudeCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_Insert; return true; }; bool isPrimitive() { return true; }; protected: }; #endif // __EXTRUDECMD_H mm3d-master/src/commands/faceoutcmd.cc000066400000000000000000000032601324021725400202210ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "faceoutcmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include #include using std::list; FaceOutCommand::FaceOutCommand() { } FaceOutCommand::~FaceOutCommand() { } bool FaceOutCommand::activated( int arg, Model * model ) { // TODO this is slow, see if we can speed it up list faces; model->getSelectedTriangles( faces ); list::iterator it; for ( it = faces.begin(); it != faces.end(); it++ ) { if ( model->triangleFacesIn( *it ) ) { model->invertNormals( *it ); } } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Normals Face Out" ).toUtf8() ); return true; } const char * FaceOutCommand::getPath() { return GEOM_NORMALS_MENU; } mm3d-master/src/commands/faceoutcmd.h000066400000000000000000000025571324021725400200730ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __FACEOUTCMD_H #define __FACEOUTCMD_H #include "command.h" class FaceOutCommand : public Command { public: FaceOutCommand(); virtual ~FaceOutCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ) { return "Normals Face Out"; }; bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __FACEOUTCMD_H mm3d-master/src/commands/flattencmd.cc000066400000000000000000000054611324021725400202350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "flattencmd.h" #include "model.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include #include #include using std::list; FlattenCommand::FlattenCommand() { } FlattenCommand::~FlattenCommand() { } const char * FlattenCommand::getName( int arg ) { switch ( arg ) { case 0: return QT_TRANSLATE_NOOP( "Command", "Flatten" ); break; case 1: return QT_TRANSLATE_NOOP( "Command", "Flatten X" ); break; case 2: return QT_TRANSLATE_NOOP( "Command", "Flatten Y" ); break; case 3: return QT_TRANSLATE_NOOP( "Command", "Flatten Z" ); break; default: break; } return "[Out of range]"; } bool FlattenCommand::activated( int arg, Model * model ) { int index; index = arg - 1; // Check for index out of range if ( index < 0 || index > 2 ) { log_error( "flatten on index %d out of range", index ); return false; } list posList; model->getSelectedPositions( posList ); if ( posList.empty() ) { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Need at least 1 vertex, joint, point, or face selected" ).toUtf8() ); return false; } float newVal = 0.0f; int countVal = 0; double coords[3]; list::iterator it; for ( it = posList.begin(); it != posList.end(); it++ ) { model->getPositionCoords( *it, coords ); newVal += coords[index]; countVal++; } newVal = newVal / (float) countVal; for ( it = posList.begin(); it != posList.end(); it++ ) { model->getPositionCoords( *it, coords ); coords[index] = newVal; model->movePosition( *it, coords[0], coords[1], coords[2] ); } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selected primitives flattened" ).toUtf8() ); return true; } mm3d-master/src/commands/flattencmd.h000066400000000000000000000024611324021725400200740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __FLATTENCMD_H #define __FLATTENCMD_H #include "command.h" class FlattenCommand : public Command { public: FlattenCommand(); virtual ~FlattenCommand(); int getCommandCount() { return 4; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __FLATTENCMD_H mm3d-master/src/commands/flipcmd.cc000066400000000000000000000054451324021725400175340ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "flipcmd.h" #include "model.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include #include #include using std::list; FlipCommand::FlipCommand() { } FlipCommand::~FlipCommand() { } const char * FlipCommand::getName( int arg ) { switch ( arg ) { case 0: return QT_TRANSLATE_NOOP( "Command", "Flip" ); break; case 1: return QT_TRANSLATE_NOOP( "Command", "Flip X" ); break; case 2: return QT_TRANSLATE_NOOP( "Command", "Flip Y" ); break; case 3: return QT_TRANSLATE_NOOP( "Command", "Flip Z" ); break; default: break; } return "[Out of range]"; } bool FlipCommand::activated( int arg, Model * model ) { int index; index = arg - 1; // Check for index out of range if ( index < 0 || index > 2 ) { log_error( "flip on index %d out of range", index ); return false; } list posList; model->getSelectedPositions( posList ); if ( posList.empty() ) { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Need at least 1 vertex, joint, point, or face selected" ).toUtf8() ); return false; } { list::iterator it; for ( it = posList.begin(); it != posList.end(); it++ ) { double coords[3]; model->getPositionCoords( *it, coords ); coords[index] = -coords[index]; model->movePosition( *it, coords[0], coords[1], coords[2] ); } } { list face; list::iterator it; model->getSelectedTriangles( face ); for ( it = face.begin(); it != face.end(); it++ ) { model->invertNormals( *it ); } } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selected primitives flipped" ).toUtf8() ); return true; } mm3d-master/src/commands/flipcmd.h000066400000000000000000000024371324021725400173740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __FLIPCMD_H #define __FLIPCMD_H #include "command.h" class FlipCommand : public Command { public: FlipCommand(); virtual ~FlipCommand(); int getCommandCount() { return 4; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __FLIPCMD_H mm3d-master/src/commands/hidecmd.cc000066400000000000000000000051541324021725400175100ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "hidecmd.h" #include "model.h" #include "modelstatus.h" #include #include #include HideCommand::HideCommand() { } HideCommand::~HideCommand() { } const char * HideCommand::getName( int arg ) { switch ( arg ) { case 0: return QT_TRANSLATE_NOOP( "Command", "Hide" ); case 1: return QT_TRANSLATE_NOOP( "Command", "Hide Unselected" ); case 2: return QT_TRANSLATE_NOOP( "Command", "Hide Selected" ); case 3: return QT_TRANSLATE_NOOP( "Command", "Unhide All" ); default: break; } return "[Out of range]"; } bool HideCommand::getKeyBinding( int arg, int & keyBinding ) { switch ( arg ) { case 0: break; case 1: keyBinding = Qt::Key_H; return true; case 2: keyBinding = Qt::Key_H + Qt::SHIFT; return true; case 3: keyBinding = Qt::Key_U; return true; default: break; } return false; } bool HideCommand::activated( int arg, Model * model ) { switch ( arg ) { case 2: model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selected primitives hidden" ).toUtf8() ); model->hideSelected(); return true; break; case 3: model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Primitives unhidden" ).toUtf8() ); model->unhideAll(); return true; break; default: model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Unselected primitives hidden" ).toUtf8() ); model->hideUnselected(); return true; break; } return false; } mm3d-master/src/commands/hidecmd.h000066400000000000000000000024141324021725400173460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __HIDECMD_H #define __HIDECMD_H #include "command.h" class HideCommand : public Command { public: HideCommand(); virtual ~HideCommand(); int getCommandCount() { return 4; }; bool getKeyBinding( int arg, int & keyBinding ); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __HIDECMD_H mm3d-master/src/commands/invertcmd.cc000066400000000000000000000030311324021725400200760ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "invertcmd.h" #include "model.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include #include InvertSelectionCommand::InvertSelectionCommand() { } InvertSelectionCommand::~InvertSelectionCommand() { } bool InvertSelectionCommand::activated( int arg, Model * model ) { if ( model ) { model->invertSelection(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Selection inverted" ).toUtf8() ); return true; } else { return false; } } const char * InvertSelectionCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Invert Selection" ); } mm3d-master/src/commands/invertcmd.h000066400000000000000000000024651324021725400177520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __INVERTCMD_H #define __INVERTCMD_H #include "command.h" class InvertSelectionCommand : public Command { public: InvertSelectionCommand(); virtual ~InvertSelectionCommand(); int getCommandCount() { return 1; }; const char * getName(int arg); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __INVERTCMD_H mm3d-master/src/commands/invnormalcmd.cc000066400000000000000000000033251324021725400206020ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "invnormalcmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include #include using std::list; InvertNormalCommand::InvertNormalCommand() { } InvertNormalCommand::~InvertNormalCommand() { } bool InvertNormalCommand::activated( int arg, Model * model ) { list faces; model->getSelectedTriangles( faces ); list::iterator it; for ( it = faces.begin(); it != faces.end(); it++ ) { model->invertNormals( *it ); } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Normals inverted" ).toUtf8() ); return true; } const char * InvertNormalCommand::getPath() { return GEOM_NORMALS_MENU; } const char * InvertNormalCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Invert Normals" ); } mm3d-master/src/commands/invnormalcmd.h000066400000000000000000000025451324021725400204470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __INVNORMALCMD_H #define __INVNORMALCMD_H #include "command.h" class InvertNormalCommand : public Command { public: InvertNormalCommand(); virtual ~InvertNormalCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __INVNORMALCMD_H mm3d-master/src/commands/jointcmd.cc000066400000000000000000000024171324021725400177210ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "jointcmd.h" #include "jointwin.h" #include "log.h" #include #include JointCommand::JointCommand() { } JointCommand::~JointCommand() { } bool JointCommand::activated( int arg, Model * model ) { JointWin * win = new JointWin( model ); win->show(); return true; } const char * JointCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Joints..." ); } mm3d-master/src/commands/jointcmd.h000066400000000000000000000025051324021725400175610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __JOINTCMD_H #define __JOINTCMD_H #include "command.h" #include class JointCommand : public Command { public: JointCommand(); virtual ~JointCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool isPrimitive() { return true; }; protected: }; #endif // __JOINTCMD_H mm3d-master/src/commands/makefacecmd.cc000066400000000000000000000045371324021725400203370ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "makefacecmd.h" #include "model.h" #include "msg.h" #include "modelstatus.h" #include "cmdmgr.h" #include "log.h" #include #include MakeFaceCommand::MakeFaceCommand() { } MakeFaceCommand::~MakeFaceCommand() { } const char * MakeFaceCommand::getPath() { return GEOM_VERTICES_MENU; } const char * MakeFaceCommand::getName( int arg ) { if ( arg == 0 ) { return QT_TRANSLATE_NOOP( "Command", "Make Face From Vertices" ); } else { return "[Out of range]"; } } bool MakeFaceCommand::getKeyBinding( int arg, int & keyBinding ) { return false; } bool MakeFaceCommand::activated( int arg, Model * model ) { if ( arg == 0 && model ) { if ( model->getAnimationMode() == Model::ANIMMODE_NONE ) { std::list verts; model->getSelectedVertices( verts ); if ( verts.size() == 3 ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Face created" ).toUtf8() ); int v1, v2, v3; std::list::iterator it = verts.begin(); v1 = *it; it++; v2 = *it; it++; v3 = *it; model->addTriangle( v1, v2, v3 ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Must select exactly 3 vertices" ).toUtf8() ); } } } return false; } mm3d-master/src/commands/makefacecmd.h000066400000000000000000000024631324021725400201750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MAKEFACECMD_H #define __MAKEFACECMD_H #include "command.h" class MakeFaceCommand : public Command { public: MakeFaceCommand(); virtual ~MakeFaceCommand(); int getCommandCount() { return 1; }; bool getKeyBinding( int arg, int & keyBinding ); const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __MAKEFACECMD_H mm3d-master/src/commands/pastecmd.cc000066400000000000000000000036261324021725400177150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "pastecmd.h" #include "model.h" #include "filtermgr.h" #include "texmgr.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include "sysconf.h" #include "misc.h" #include #include #include #include using std::list; using std::map; PasteCommand::PasteCommand() { } PasteCommand::~PasteCommand() { } bool PasteCommand::activated( int arg, Model * model ) { if ( model ) { Model * m = new Model; std::string clipfile = getMm3dHomeDirectory(); clipfile += "/clipboard"; mkpath( clipfile.c_str(), 0755 ); clipfile += "/clipboard.mm3d"; FilterManager::getInstance()->readFile( m, clipfile.c_str() ); model->mergeModels( m, true, Model::AM_NONE, false ); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Paste complete" ).toUtf8() ); return true; } else { return false; } } const char * PasteCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Paste from Clipboard" ); } mm3d-master/src/commands/pastecmd.h000066400000000000000000000025041324021725400175510ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PASTECMD_H #define __PASTECMD_H #include "command.h" #include class PasteCommand : public Command { public: PasteCommand(); virtual ~PasteCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __PASTECMD_H mm3d-master/src/commands/pointcmd.cc000066400000000000000000000024201324021725400177210ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "pointcmd.h" #include "pointwin.h" #include "log.h" #include #include PointCommand::PointCommand() { } PointCommand::~PointCommand() { } bool PointCommand::activated( int arg, Model * model ) { PointWin * win = new PointWin( model ); win->show(); return true; } const char * PointCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Points..." ); } mm3d-master/src/commands/pointcmd.h000066400000000000000000000025051324021725400175670ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POINTCMD_H #define __POINTCMD_H #include "command.h" #include class PointCommand : public Command { public: PointCommand(); virtual ~PointCommand(); int getCommandCount() { return 1; }; const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool isPrimitive() { return true; }; protected: }; #endif // __POINTCMD_H mm3d-master/src/commands/rotatetexcmd.cc000066400000000000000000000103451324021725400206140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "rotatetexcmd.h" #include "model.h" #include "msg.h" #include "modelstatus.h" #include "cmdmgr.h" #include "log.h" #include #include RotateTextureCommand::RotateTextureCommand() { } RotateTextureCommand::~RotateTextureCommand() { } const char * RotateTextureCommand::getPath() { return GEOM_FACES_MENU; } const char * RotateTextureCommand::getName( int arg ) { switch ( arg ) { case 0: return QT_TRANSLATE_NOOP( "Command", "Rotate Texture Coordinates" ); break; case 1: return QT_TRANSLATE_NOOP( "Command", "Face" ); break; case 2: return QT_TRANSLATE_NOOP( "Command", "Group" ); break; default: break; } return "[Out of range]"; } bool RotateTextureCommand::getKeyBinding( int arg, int & keyBinding ) { return false; } bool RotateTextureCommand::activated( int arg, Model * model ) { if ( arg == 1 && model ) { if ( model->getAnimationMode() == Model::ANIMMODE_NONE ) { std::list tris; model->getSelectedTriangles( tris ); if ( tris.size() > 0 ) { std::list::iterator it; float s, t; float oldS, oldT; for ( it = tris.begin(); it != tris.end(); it++ ) { model->getTextureCoords( *it, 2, oldS, oldT ); model->getTextureCoords( *it, 1, s, t ); model->setTextureCoords( *it, 2, s, t ); model->getTextureCoords( *it, 0, s, t ); model->setTextureCoords( *it, 1, s, t ); model->setTextureCoords( *it, 0, oldS, oldT ); } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Texture coordinates rotated" ).toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Must select faces" ).toUtf8() ); } } } if ( arg == 2 && model ) { if ( model->getAnimationMode() == Model::ANIMMODE_NONE ) { std::list tris; model->getSelectedTriangles( tris ); if ( tris.size() > 0 ) { std::list::iterator it; float s; float t; float temp; for ( it = tris.begin(); it != tris.end(); it++ ) { model->getTextureCoords( *it, 0, s, t ); temp = s; s = 0.5 - (t - 0.5); t = temp; model->setTextureCoords( *it, 0, s, t ); model->getTextureCoords( *it, 1, s, t ); temp = s; s = 0.5 - (t - 0.5); t = temp; model->setTextureCoords( *it, 1, s, t ); model->getTextureCoords( *it, 2, s, t ); temp = s; s = 0.5 - (t - 0.5); t = temp; model->setTextureCoords( *it, 2, s, t ); } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Texture coordinates rotated" ).toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "Must select faces" ).toUtf8() ); } } } return false; } mm3d-master/src/commands/rotatetexcmd.h000066400000000000000000000025051324021725400204550ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ROTATETEXCMD_H #define __ROTATETEXCMD_H #include "command.h" class RotateTextureCommand : public Command { public: RotateTextureCommand(); virtual ~RotateTextureCommand(); int getCommandCount() { return 3; }; bool getKeyBinding( int arg, int & keyBinding ); const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __ROTATETEXCMD_H mm3d-master/src/commands/selectfreecmd.cc000066400000000000000000000033251324021725400207160ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include #include #include #include "selectfreecmd.h" #include "model.h" #include "msg.h" #include "modelstatus.h" SelectFreeCommand::SelectFreeCommand() { } SelectFreeCommand::~SelectFreeCommand() { } const char * SelectFreeCommand::getPath() { return GEOM_VERTICES_MENU; } const char * SelectFreeCommand::getName( int arg ) { if ( arg == 0 ) { return QT_TRANSLATE_NOOP( "Command", "Select Free Vertices" ); } else { return "[Out of range]"; } } bool SelectFreeCommand::activated( int arg, Model * model ) { if ( model ) { model->selectFreeVertices(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Free-floating vertices selected" ).toUtf8() ); return true; } else { return false; } } mm3d-master/src/commands/selectfreecmd.h000066400000000000000000000024001324021725400205510ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTFREE_H #define __SELECTFREE_H #include "command.h" class SelectFreeCommand : public Command { public: SelectFreeCommand(); virtual ~SelectFreeCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __SELECTFREE_H mm3d-master/src/commands/simplifycmd.cc000066400000000000000000000026361324021725400204350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "simplifycmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include SimplifyMeshCommand::SimplifyMeshCommand() { } SimplifyMeshCommand::~SimplifyMeshCommand() { } bool SimplifyMeshCommand::activated( int arg, Model * model ) { model->simplifySelectedMesh(); return true; } const char * SimplifyMeshCommand::getPath() { return GEOM_MESHES_MENU; } const char * SimplifyMeshCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Simplify Mesh" ); } mm3d-master/src/commands/simplifycmd.h000066400000000000000000000024271324021725400202750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SIMPLIFYCMD_H #define __SIMPLIFYCMD_H #include "command.h" class SimplifyMeshCommand : public Command { public: SimplifyMeshCommand(); virtual ~SimplifyMeshCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __SIMPLIFYCMD_H mm3d-master/src/commands/snapcmd.cc000066400000000000000000000141261324021725400175370ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2005 Johannes Kroll * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // Integrated into MM3D by Kevin Worcester // This code is modified from the snap_together plugin written by Johannes Kroll #include "menuconf.h" #include "snapcmd.h" #include "cmdmgr.h" #include "model.h" #include "pluginapi.h" #include "version.h" #include "log.h" #include "weld.h" #include #include #include #include #include #include SnapCommand::SnapCommand() { } SnapCommand::~SnapCommand() { } // set the coordinates of all the selected vertices to their arithmetic mean. static void snap_together(Model *model, list selection) { double coord[3]= { 0, 0, 0 }, coord_temp[3]; list::iterator iter; for(iter= selection.begin(); iter!=selection.end(); iter++) { model->getVertexCoords(*iter, coord_temp); coord[0]+= coord_temp[0]; coord[1]+= coord_temp[1]; coord[2]+= coord_temp[2]; } coord[0]/= selection.size(); coord[1]/= selection.size(); coord[2]/= selection.size(); for(iter= selection.begin(); iter!=selection.end(); iter++) { model->moveVertex(*iter, coord[0], coord[1], coord[2]); } } // snap 2 vertices together, delete one of them, and take care of affected triangles. static void snap_together_two(Model *model, int v0, int v1) { double coord_v0[3], coord_v1[3]; model->getVertexCoords(v0, coord_v0); model->getVertexCoords(v1, coord_v1); coord_v0[0]= (coord_v0[0]+coord_v1[0]) / 2; coord_v0[1]= (coord_v0[1]+coord_v1[1]) / 2; coord_v0[2]= (coord_v0[2]+coord_v1[2]) / 2; model->moveVertex(v0, coord_v0[0], coord_v0[1], coord_v0[2]); model->moveVertex(v1, coord_v0[0], coord_v0[1], coord_v0[2]); } // find the nearest vertex in the selection which is not contained in the exclude (already processed) list. #define DISTANCE(x, y, z) sqrt( (x)*(x) + (y)*(y) + (z)*(z) ) int find_nearest_vertex(Model *model, int vertex, list selection, list exclude) { double smallest_distance= 0xdeadbeef; int nearest_vertex= -1; double coord[3], coord_temp[3]; list::iterator iter; model->getVertexCoords(vertex, coord); for(iter= selection.begin(); iter!=selection.end(); iter++) { if(*iter!=vertex) { list::iterator it= exclude.begin(); while(it!=exclude.end() && *it != *iter) it++; if( *it != *iter ) { model->getVertexCoords( *iter, coord_temp ); double distance= DISTANCE(coord_temp[0]-coord[0], coord_temp[1]-coord[1], coord_temp[2]-coord[2]); if(distance < smallest_distance) { smallest_distance= distance; nearest_vertex= *iter; } } } } return nearest_vertex; } const char * SnapCommand::getPath() { return GEOM_VERTICES_MENU; } const char * SnapCommand::getName( int arg ) { switch ( arg ) { case 0: default: return QT_TRANSLATE_NOOP( "Command", "Snap Vertices Together" ); break; case 1: return QT_TRANSLATE_NOOP( "Command", "Snap All Selected" ); break; case 2: return QT_TRANSLATE_NOOP( "Command", "Snap Nearest Selected" ); break; case 3: return QT_TRANSLATE_NOOP( "Command", "Snap All and Weld" ); break; case 4: return QT_TRANSLATE_NOOP( "Command", "Snap Nearest and Weld" ); break; } return ""; } bool SnapCommand::activated( int arg, Model * model ) { list selection; model->getSelectedVertices( selection ); if ( selection.size() >= 2 ) { if ( arg == 1 || arg == 3 ) { snap_together(model, selection); } else { list excludelist; list::iterator sel_iter; for ( sel_iter = selection.begin(); sel_iter != selection.end(); sel_iter++ ) { list::iterator it = excludelist.begin(); while ( it != excludelist.end() && *it != *sel_iter ) { it++; } if ( *it != *sel_iter ) { int nearest_vertex= find_nearest_vertex(model, *sel_iter, selection, excludelist); if ( nearest_vertex != -1 ) { snap_together_two( model, *sel_iter, nearest_vertex ); excludelist.push_back(*sel_iter); excludelist.push_back(nearest_vertex); } } } } if ( arg == 3 || arg == 4 ) { weldSelectedVertices( model ); } model->deleteOrphanedVertices(); return true; } else { return false; } } #ifdef PLUGIN //------------------------------------------------------------------ // Plugin functions //------------------------------------------------------------------ extern "C" bool plugin_init() { CommandManager::getInstance()->registerCommand( new SnapCommand() ); log_debug( "Snap Together Plugin Initialized\n" ); return true; } // We have no cleanup to do extern "C" bool plugin_uninit() { return true; } extern "C" const char * plugin_version() { return "1.0.0"; } extern "C" const char * plugin_mm3d_version() { return VERSION_STRING; } extern "C" const char * plugin_desc() { return "Snap Vertices Together"; } #endif // PLUGIN mm3d-master/src/commands/snapcmd.h000066400000000000000000000041521324021725400173770ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2005 Johannes Kroll * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SNAPCMD_H #define __SNAPCMD_H #include "command.h" class SnapCommand: public Command { public: SnapCommand(); virtual ~SnapCommand(); int getCommandCount() { return 5; } const char * getPath(); const char * getName( int arg ); // If you want a keybinding for your command you must set keyBinding // and return true. The value of keyBinding is a key code as defined // in qnamespace.h (part of the Qt library). bool getKeyBinding( int arg, int & keyBinding ) { return false; }; // activated means that the user wants to run the command specified in arg // on the specified model. // // A return value of 'true' means that the model was modified by the // command. 'false' means the model was unmodified. An unmodified // model may be the result of a canceled dialog box, or an empty // selection set. bool activated( int arg, Model * model ); // The following functions determine how the tools are grouped in // menus. // Does this command operate on primitives (vertices, triangles, joints)? bool isPrimitive() { return true; }; // Does this command operate on groups of polygons? bool isGroup() { return false; }; }; #endif // __SNAPCMD_H mm3d-master/src/commands/spherifycmd.cc000066400000000000000000000026241324021725400204270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "spherifycmd.h" #include "spherifywin.h" #include "log.h" #include #include SpherifyCommand::SpherifyCommand() { } SpherifyCommand::~SpherifyCommand() { } bool SpherifyCommand::activated( int arg, Model * model ) { SpherifyWin * win = new SpherifyWin( model, NULL ); win->show(); return true; } const char * SpherifyCommand::getPath() { return GEOM_MESHES_MENU; } const char * SpherifyCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Spherify..." ); } mm3d-master/src/commands/spherifycmd.h000066400000000000000000000025641324021725400202740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SPHERIFYCMD_H #define __SPHERIFYCMD_H #include "command.h" #include class SpherifyCommand : public Command { public: SpherifyCommand(); virtual ~SpherifyCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { return false; }; bool isPrimitive() { return true; }; protected: }; #endif // __SPHERIFYCMD_H mm3d-master/src/commands/subdividecmd.cc000066400000000000000000000030101324021725400205420ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "subdividecmd.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include #include SubdivideCommand::SubdivideCommand() { } SubdivideCommand::~SubdivideCommand() { } bool SubdivideCommand::activated( int arg, Model * model ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Command", "Subdivide complete" ).toUtf8() ); model->subdivideSelectedTriangles(); return true; } const char * SubdivideCommand::getPath() { return GEOM_FACES_MENU; } const char * SubdivideCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Subdivide Faces" ); } mm3d-master/src/commands/subdividecmd.h000066400000000000000000000024021324021725400204100ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SUBDIVIDECMD_H #define __SUBDIVIDECMD_H #include "command.h" class SubdivideCommand : public Command { public: SubdivideCommand(); virtual ~SubdivideCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; }; #endif // __SUBDIVIDECMD_H mm3d-master/src/commands/unweldcmd.cc000066400000000000000000000040501324021725400200670ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "unweldcmd.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "weld.h" // does the real work #include #include #include using std::list; UnweldCommand::UnweldCommand() { } UnweldCommand::~UnweldCommand() { } bool UnweldCommand::activated( int arg, Model * model ) { if ( model ) { std::list vert; model->getSelectedVertices( vert ); if ( !vert.empty() ) { int unwelded = 0; int welded = 0; unweldSelectedVertices( model, unwelded, welded ); model_status( model, StatusNormal, STATUSTIME_SHORT, (qApp->translate( "Command", "Unwelded %1 vertices into %2 vertices" ).arg(welded).arg(unwelded)).toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have 1 or more vertices selected to unweld." ).toUtf8() ); } } return false; } const char * UnweldCommand::getPath() { return GEOM_VERTICES_MENU; } const char * UnweldCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Unweld Vertices" ); } mm3d-master/src/commands/unweldcmd.h000066400000000000000000000026241324021725400177360ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __UNWELDCMD_H #define __UNWELDCMD_H #include "command.h" #include class UnweldCommand : public Command { public: UnweldCommand(); virtual ~UnweldCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); //bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::SHIFT+Qt::CTRL+Qt::Key_W; return true; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __UNWELDCMD_H mm3d-master/src/commands/weldcmd.cc000066400000000000000000000040641324021725400175310ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "weldcmd.h" #include "model.h" #include "glmath.h" #include "log.h" #include "msg.h" #include "modelstatus.h" #include "weld.h" #include #include #include #include using std::list; using std::map; WeldCommand::WeldCommand() { } WeldCommand::~WeldCommand() { } bool WeldCommand::activated( int arg, Model * model ) { if ( model ) { list vert; model->getSelectedVertices( vert ); if ( vert.size() > 1 ) { int unwelded = 0; int welded = 0; weldSelectedVertices( model, 0.0001, unwelded, welded ); model_status( model, StatusNormal, STATUSTIME_SHORT, (qApp->translate( "Command", "Welded %1 vertices into %2 vertices" ).arg(unwelded).arg(welded)).toUtf8() ); return true; } else { model_status( model, StatusError, STATUSTIME_LONG, qApp->translate( "Command", "You must have 2 or more vertices selected to weld." ).toUtf8() ); } } return false; } const char * WeldCommand::getPath() { return GEOM_VERTICES_MENU; } const char * WeldCommand::getName( int arg ) { return QT_TRANSLATE_NOOP( "Command", "Weld Vertices" ); } mm3d-master/src/commands/weldcmd.h000066400000000000000000000025741324021725400173770ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __WELDCMD_H #define __WELDCMD_H #include "command.h" #include class WeldCommand : public Command { public: WeldCommand(); virtual ~WeldCommand(); int getCommandCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::CTRL+Qt::Key_W; return true; }; bool activated( int arg, Model * model ); bool isPrimitive() { return true; }; protected: }; #endif // __WELDCMD_H mm3d-master/src/depui/000077500000000000000000000000001324021725400151045ustar00rootroot00000000000000mm3d-master/src/depui/Makefile.am000066400000000000000000000011311324021725400171340ustar00rootroot00000000000000noinst_LIBRARIES = libdepui.a libdepui_HFILES = \ errorobj.h \ modelviewport.h \ textureframe.h \ texwidget.h libdepui_MOC = \ errorobj.moc.cc \ modelviewport.moc.cc \ textureframe.moc.cc \ texwidget.moc.cc libdepui_a_SOURCES = \ errorobj.cc \ modelviewport.cc \ textureframe.cc \ texwidget.cc \ $(libdepui_MOC) \ $(libdepui_HFILES) %.moc.cc: %.h $(QT_MOC) -o $@ $< AM_CPPFLAGS = $(CORE_PROFILE) $(COVFLAGS) -Wall -I../libmm3d -I../mm3dcore -I../ -DMM3D_EDIT $(all_includes) $(QT_CXXFLAGS) $(LUALIB_CCFLAGS) $(GL_CFLAGS) CLEANFILES = $(libdepui_MOC) *.gcno *.gcda mm3d-master/src/depui/errorobj.cc000066400000000000000000000102571324021725400172440ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "errorobj.h" ErrorObject g_errorObject; ErrorObject::ErrorObject( QObject * parent ) : QObject( parent ) { } ErrorObject::~ErrorObject() { } QString ErrorObject::getModelErrorString( Model::ModelErrorE err, Model * model ) { switch ( err ) { case Model::ERROR_NONE: return tr("Success"); case Model::ERROR_CANCEL: return tr("Canceled"); case Model::ERROR_UNKNOWN_TYPE: return tr("Unrecognized file extension (unknown type)"); case Model::ERROR_UNSUPPORTED_OPERATION: return tr("Operation not supported for this file type"); case Model::ERROR_BAD_ARGUMENT: return tr("Invalid argument (internal error)"); case Model::ERROR_NO_FILE: return tr("File does not exist"); case Model::ERROR_NO_ACCESS: return tr("Permission denied"); case Model::ERROR_FILE_OPEN: return tr("Could not open file"); case Model::ERROR_FILE_READ: return tr("Could not read from file"); case Model::ERROR_BAD_MAGIC: return tr("File is the wrong type or corrupted"); case Model::ERROR_UNSUPPORTED_VERSION: return tr("Unsupported version"); case Model::ERROR_BAD_DATA: return tr("File contains invalid data"); case Model::ERROR_UNEXPECTED_EOF: return tr("Unexpected end of file"); case Model::ERROR_EXPORT_ONLY: return tr("Write not supported, try \"Export...\""); case Model::ERROR_FILTER_SPECIFIC: if ( model ) { return QString::fromUtf8( model->getFilterSpecificError() ); } else { return QString::fromUtf8( Model::getLastFilterSpecificError() ); } case Model::ERROR_UNKNOWN: return tr("Unknown error"); default: break; } return QString("FIXME: Untranslated model error"); } QString ErrorObject::getTextureErrorString( Texture::ErrorE err ) { switch ( err ) { case Texture::ERROR_NONE: return tr("Success"); case Texture::ERROR_NO_FILE: return tr("File does not exist"); case Texture::ERROR_NO_ACCESS: return tr("Permission denied"); case Texture::ERROR_FILE_OPEN: return tr("Could not open file"); case Texture::ERROR_FILE_READ: return tr("Could not read from file"); case Texture::ERROR_FILE_WRITE: return tr("Could not write file"); case Texture::ERROR_BAD_MAGIC: return tr("File is the wrong type or corrupted"); case Texture::ERROR_UNSUPPORTED_VERSION: return tr("Unsupported version"); case Texture::ERROR_BAD_DATA: return tr("File contains invalid data"); case Texture::ERROR_UNEXPECTED_EOF: return tr("Unexpected end of file"); case Texture::ERROR_UNSUPPORTED_OPERATION: return tr("This operation is not supported"); case Texture::ERROR_BAD_ARGUMENT: return tr("Invalid argument (internal error)"); case Texture::ERROR_UNKNOWN: return tr("Unknown error"); default: break; } return QString("FIXME: Untranslated texture error"); } QString modelErrStr( Model::ModelErrorE err, Model * model ) { return g_errorObject.getModelErrorString( err, model ); } QString textureErrStr( Texture::ErrorE err ) { return g_errorObject.getTextureErrorString( err ); } mm3d-master/src/depui/errorobj.h000066400000000000000000000027121324021725400171030ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ERROROBJ_H #define __ERROROBJ_H #include #include #include "model.h" #include "texture.h" class ErrorObject : public QObject { Q_OBJECT public: ErrorObject( QObject * parent = NULL ); virtual ~ErrorObject( ); QString getModelErrorString( Model::ModelErrorE err, Model * model = NULL ); QString getTextureErrorString( Texture::ErrorE err ); }; extern ErrorObject g_errorObject; // Convenience functions QString modelErrStr( Model::ModelErrorE err, Model * model = NULL ); QString textureErrStr( Texture::ErrorE err ); #endif // __ERROROBJ_H mm3d-master/src/depui/modelviewport.cc000066400000000000000000002404171324021725400203230ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "model.h" #include "toolbox.h" #include "tool.h" #include "glmath.h" #include "decalmgr.h" #include "decal.h" #include "log.h" #include "modelstatus.h" #include "texmgr.h" #include "modelviewport.h" #include "3dmprefs.h" #include "mm3dport.h" #include "pixmap/arrow.xpm" #include "pixmap/crosshairrow.xpm" #include #include #include #include #include #include #include #include #include #include #define NEWVIEWPORT #define VP_ZOOMSCALE 0.75 #define MM3D_ENABLEALPHA static int const SCROLL_SIZE = 16; struct _ScrollButton_t { int x; int y; int texIndex; float s1; float t1; float s2; float t2; float s3; float t3; float s4; float t4; }; typedef struct _ScrollButton_t ScrollButtonT; static ScrollButtonT s_buttons[ ModelViewport::ScrollButtonMAX ] = { { -18, -18, 1, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Pan { -52, -18, 0, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }, // Left { -35, -18, 0, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, // Right { -18, -35, 0, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Up { -18, -52, 0, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, // Down }; static Matrix s_mat; ModelViewport::ModelViewport( QWidget * parent ) : QGLWidget( parent ), m_model( NULL ), m_operation( MO_None ), m_activeButton( Qt::NoButton ), m_viewDirection( ViewFront ), m_centerX( 0.0 ), m_centerY( 0.0 ), m_centerZ( 0.0 ), m_rotX( 0.0 ), m_rotY( 0.0 ), m_rotZ( 0.0 ), m_zoomLevel( 32.0 ), m_unitWidth( 1.0 ), m_far( 10000.0 ), m_near( 1.0 ), m_farOrtho( 1000000.0 ), m_nearOrtho( 0.001 ), m_viewportWidth( 0 ), m_viewportHeight( 0 ), m_scrollTimer( new QTimer() ), m_overlayButton( ScrollButtonMAX ), m_capture( false ), m_texturesLoaded( false ), m_toolbox( NULL ) { // Default preferences m_arcballPoint[0] = 0.0; m_arcballPoint[1] = 0.0; m_arcballPoint[2] = 0.0; m_scrollTimer->setSingleShot( true ); g_prefs.setDefault( "ui_grid_inc", 4.0 ); g_prefs.setDefault( "ui_3dgrid_inc", 4.0 ); g_prefs.setDefault( "ui_3dgrid_count", 6 ); g_prefs.setDefault( "ui_3dgrid_xy", 0 ); g_prefs.setDefault( "ui_3dgrid_xz", 1 ); g_prefs.setDefault( "ui_3dgrid_yz", 0 ); setAutoBufferSwap( false ); setFocusPolicy( Qt::WheelFocus ); setMinimumSize( 220, 180 ); double rot[3] = { 45 * PIOVER180, 0, 0 }; s_mat.setRotation( rot ); m_backColor.setRgb( 130, 200, 200 ); setAcceptDrops( true ); setMouseTracking( true ); QPixmap arrow( arrow_xpm ); QPixmap cross( crosshairrow_xpm ); QImage img; makeCurrent(); glGenTextures( 2, m_scrollTextures ); img = arrow.toImage(); makeTextureFromImage( img, m_scrollTextures[0] ); img = cross.toImage(); makeTextureFromImage( img, m_scrollTextures[1] ); connect( m_scrollTimer, SIGNAL(timeout()), this, SLOT(scrollTimeout())); setCursor( Qt::ArrowCursor ); } ModelViewport::~ModelViewport() { log_debug( "deleting model viewport\n" ); makeCurrent(); glDeleteTextures( 1, &m_backgroundTexture ); glDeleteTextures( 2, m_scrollTextures ); freeTextures(); delete m_scrollTimer; } void ModelViewport::freeTextures() { log_debug( "freeing texture for viewport\n" ); makeCurrent(); if ( m_model ) { m_model->removeContext( static_cast( this ) ); } } void ModelViewport::initializeGL() { glShadeModel( GL_SMOOTH ); glClearColor( m_backColor.red() / 256.0, m_backColor.green() / 256.0, m_backColor.blue() / 256.0, 1.0f ); glClearDepth( 1.0f ); glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LEQUAL ); glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); { GLfloat ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat diffuse[] = { 0.9f, 0.9f, 0.9f, 1.0f }; GLfloat position[] = { 0.0f, 0.0f, 1.0f, 0.0f }; glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE ); glLightfv( GL_LIGHT0, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_POSITION, position ); //glEnable( GL_LIGHT0 ); } { GLfloat ambient[] = { 0.8f, 0.4f, 0.4f, 1.0f }; GLfloat diffuse[] = { 0.9f, 0.5f, 0.5f, 1.0f }; GLfloat position[] = { 0.0f, 0.0f, 1.0f, 0.0f }; glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE ); glLightfv( GL_LIGHT1, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT1, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT1, GL_POSITION, position ); //glEnable( GL_LIGHT1 ); } { GLint texSize = 0; glGetIntegerv( GL_MAX_TEXTURE_SIZE, &texSize ); log_debug( "max texture size is %dx%d\n", texSize, texSize ); } glGenTextures( 1, &m_backgroundTexture ); checkGlErrors(); #ifdef MM3D_ENABLEALPHA glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); if ( ! glIsEnabled( GL_BLEND) ) { log_warning( "alpha not supported\n" ); glDisable( GL_BLEND ); glGetError(); // clear errors } #endif // MM3D_ENABLEALPHA } void ModelViewport::resizeGL( int w, int h ) { if ( h == 0 ) { h = 1; } m_viewportWidth = w; m_viewportHeight = h; adjustViewport(); } void ModelViewport::paintGL() { //LOG_PROFILE(); if ( m_inOverlay ) { setViewportDraw(); } if ( m_capture ) { glClearColor( 130.0 / 256.0, 200.0 / 256.0, 200.0 / 256.0, 1.0f ); } float viewPoint[4] = { 0.0f, 0.0f, 0.0f, 1.0f }; if ( m_viewDirection == ViewPerspective || m_viewDirection == ViewOrtho ) { glEnable( GL_LIGHT0 ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); //if ( m_viewDirection == ViewPerspective ) { glLoadIdentity( ); } #ifdef NEWVIEWPORT viewPoint[0] = m_arcballPoint[0]; // m_centerX; viewPoint[1] = m_arcballPoint[1]; // m_centerY; viewPoint[2] = m_arcballPoint[2] + (m_zoomLevel * 2.0); if ( m_viewDirection == ViewPerspective ) { glTranslatef( -viewPoint[0], -viewPoint[1], -viewPoint[2] ); } else { glTranslatef( 0.0, 0.0, -m_farOrtho / 2.0 ); } glRotatef( m_rotZ, 0.0, 0.0, 1.0); glRotatef( m_rotY, 0.0, 1.0, 0.0); glRotatef( m_rotX, 1.0, 0.0, 0.0); #else viewPoint[0] = m_centerX; viewPoint[1] = m_centerY; viewPoint[2] = (m_zoomLevel * 2.0); glTranslatef( -viewPoint[0], -viewPoint[1], -viewPoint[2] ); glRotatef( m_rotZ, 0.0, 0.0, 1.0); glRotatef( m_rotY, 0.0, 1.0, 0.0); glRotatef( m_rotX, 1.0, 0.0, 0.0); #endif // NEWVIEWPORT Matrix m; m.setRotationInDegrees( 0.0f, 0.0f, -m_rotZ ); m.apply( viewPoint ); m.setRotationInDegrees( 0.0f, -m_rotY, 0.0f ); m.apply( viewPoint ); m.setRotationInDegrees( -m_rotX, 0.0f, 0.0f ); m.apply( viewPoint ); } else { glDisable( GL_LIGHT0 ); glDisable( GL_LIGHT1 ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLoadIdentity( ); viewPoint[0] = 0.0f; viewPoint[1] = 0.0f; viewPoint[2] = 500000.0f; glTranslatef( -viewPoint[0], -viewPoint[1], -viewPoint[2] ); Matrix m; switch ( m_viewDirection ) { case ViewFront: // do nothing break; case ViewBack: glRotatef( 180.0, 0.0, 1.0, 0.0); m.setRotationInDegrees( 0.0f, -180.0f, 0.0f ); break; case ViewLeft: glRotatef( -90.0, 0.0, 1.0, 0.0); m.setRotationInDegrees( 0.0f, 90.0f, 0.0f ); break; case ViewRight: glRotatef( 90.0, 0.0, 1.0, 0.0); m.setRotationInDegrees( 0.0f, -90.0f, 0.0f ); break; case ViewTop: glRotatef( 90.0, 1.0, 0.0, 0.0); m.setRotationInDegrees( -90.0f, 0.0f, 0.0f ); break; case ViewBottom: glRotatef( -90.0, 1.0, 0.0, 0.0); m.setRotationInDegrees( 90.0f, 0.0f, 0.0f ); break; default: log_error( "Unknown ViewDirection: %d\n", m_viewDirection ); swapBuffers(); return; break; } m.apply( viewPoint ); } if ( !m_capture ) { drawGridLines(); } if ( m_model ) { glColor3f( 0.7, 0.7, 0.7 ); if ( m_viewDirection == ViewPerspective ) { glEnable( GL_LIGHTING ); int opt = Model::DO_TEXTURE | Model::DO_SMOOTHING | ( (g_prefs( "ui_render_bad_textures" ).intValue() == 0) ? 0 : Model::DO_BADTEX); bool drawSelections = (g_prefs( "ui_render_3d_selections" ).intValue() == 0) ? false : true; switch ( m_model->getPerspectiveDrawMode() ) { case ViewWireframe: opt = Model::DO_WIREFRAME; drawSelections = true; break; case ViewFlat: opt = Model::DO_NONE; break; case ViewSmooth: opt = Model::DO_SMOOTHING; break; case ViewAlpha: opt = opt | Model::DO_ALPHA; break; default: break; } opt |= ( (g_prefs( "ui_render_backface_cull" ).intValue() == 0) ? 0 : Model::DO_BACKFACECULL); if ( drawSelections ) { glDisable( GL_LIGHTING ); m_model->drawLines(); m_model->drawVertices(); } if ( opt != Model::DO_WIREFRAME ) { glEnable( GL_LIGHTING ); m_model->draw( opt, static_cast( this) , viewPoint ); } if ( drawSelections ) { glDisable( GL_LIGHTING ); glDisable( GL_DEPTH_TEST ); m_model->drawJoints(); } glDisable( GL_LIGHTING ); glDisable( GL_DEPTH_TEST ); m_model->drawPoints(); m_model->drawProjections(); } else { // Draw background drawBackground(); glClear( GL_DEPTH_BUFFER_BIT ); m_model->drawLines(); m_model->drawVertices(); int drawMode = m_model->getCanvasDrawMode(); if ( drawMode != ViewWireframe ) { glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); int opt = Model::DO_TEXTURE | Model::DO_SMOOTHING | ( (g_prefs( "ui_render_bad_textures" ).intValue() == 0) ? 0 : Model::DO_BADTEX); switch ( drawMode ) { case ViewFlat: opt = Model::DO_NONE; break; case ViewSmooth: opt = Model::DO_SMOOTHING; break; case ViewAlpha: opt = opt | Model::DO_ALPHA; break; default: break; } opt |= ( (g_prefs( "ui_render_backface_cull" ).intValue() == 0) ? 0 : Model::DO_BACKFACECULL); m_model->draw( opt, static_cast( this ), viewPoint ); glDisable( GL_LIGHTING ); } glDisable( GL_DEPTH_TEST ); m_model->drawJoints(); m_model->drawPoints(); m_model->drawProjections(); for ( DecalList::iterator it = m_decals.begin(); it != m_decals.end(); it++ ) { (*it)->draw(); } glEnable( GL_DEPTH_TEST ); } } glDisable( GL_LIGHTING ); glDisable( GL_TEXTURE_2D ); if ( !m_capture ) { drawOrigin(); } else { glEnable( GL_DEPTH_TEST ); } if ( this->hasFocus() ) { drawOverlay(); } checkGlErrors(); swapBuffers(); } void ModelViewport::drawGridLines() { if ( m_viewDirection == ViewPerspective || m_viewDirection == ViewOrtho ) { double inc = g_prefs( "ui_3dgrid_inc" ).doubleValue(); double max = g_prefs( "ui_3dgrid_count" ).doubleValue() * inc; double x; double y; double z; glColor3f( 0.55f, 0.55f, 0.55f ); glBegin( GL_LINES ); if ( g_prefs( "ui_3dgrid_xy" ).intValue() != 0 ) { for ( x = -max; x <= max; x += inc ) { glVertex3f( x, -max, 0 ); glVertex3f( x, +max, 0 ); } for ( y = -max; y <= max; y += inc ) { glVertex3f( -max, y, 0 ); glVertex3f( +max, y, 0 ); } } if ( g_prefs( "ui_3dgrid_xz" ).intValue() != 0 ) { for ( x = -max; x <= max; x += inc ) { glVertex3f( x, 0, -max ); glVertex3f( x, 0, +max ); } for ( z = -max; z <= max; z += inc ) { glVertex3f( -max, 0, z ); glVertex3f( +max, 0, z ); } } if ( g_prefs( "ui_3dgrid_yz" ).intValue() != 0 ) { for ( y = -max; y <= max; y += inc ) { glVertex3f( 0, y, -max ); glVertex3f( 0, y, +max ); } for ( z = -max; z <= max; z += inc ) { glVertex3f( 0, -max, z ); glVertex3f( 0, +max, z ); } } glEnd(); } else { m_unitWidth = getUnitWidth(); double xRangeMin = 0; double xRangeMax = 0; double yRangeMin = 0; double yRangeMax = 0; double xStart = 0; double yStart = 0; double x = 0; double y = 0; glColor3f( 0.55f, 0.55f, 0.55f ); glBegin( GL_LINES ); switch ( m_viewDirection ) { case ViewFront: xRangeMin = m_arcballPoint[0] - (m_width / 2.0); xRangeMax = m_arcballPoint[0] + (m_width / 2.0); yRangeMin = m_arcballPoint[1] - (m_height / 2.0); yRangeMax = m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( x, yRangeMin, 0 ); glVertex3f( x, yRangeMax, 0 ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( xRangeMin, y, 0 ); glVertex3f( xRangeMax, y, 0 ); } break; case ViewBack: xRangeMin = -m_arcballPoint[0] - (m_width / 2.0); xRangeMax = -m_arcballPoint[0] + (m_width / 2.0); yRangeMin = m_arcballPoint[1] - (m_height / 2.0); yRangeMax = m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( x, yRangeMin, 0 ); glVertex3f( x, yRangeMax, 0 ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( xRangeMin, y, 0 ); glVertex3f( xRangeMax, y, 0 ); } break; case ViewLeft: xRangeMin = -m_arcballPoint[0] - (m_width / 2.0); xRangeMax = -m_arcballPoint[0] + (m_width / 2.0); yRangeMin = m_arcballPoint[1] - (m_height / 2.0); yRangeMax = m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( 0, yRangeMin, x ); glVertex3f( 0, yRangeMax, x ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( 0, y, xRangeMin ); glVertex3f( 0, y, xRangeMax ); } break; case ViewRight: xRangeMin = m_arcballPoint[0] - (m_width / 2.0); xRangeMax = m_arcballPoint[0] + (m_width / 2.0); yRangeMin = m_arcballPoint[1] - (m_height / 2.0); yRangeMax = m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( 0, yRangeMin, x ); glVertex3f( 0, yRangeMax, x ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( 0, y, xRangeMin ); glVertex3f( 0, y, xRangeMax ); } break; case ViewTop: xRangeMin = m_arcballPoint[0] - (m_width / 2.0); xRangeMax = m_arcballPoint[0] + (m_width / 2.0); yRangeMin = -m_arcballPoint[1] - (m_height / 2.0); yRangeMax = -m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( x, 0, yRangeMin ); glVertex3f( x, 0, yRangeMax ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( xRangeMin, 0, y ); glVertex3f( xRangeMax, 0, y ); } break; case ViewBottom: xRangeMin = m_arcballPoint[0] - (m_width / 2.0); xRangeMax = m_arcballPoint[0] + (m_width / 2.0); yRangeMin = m_arcballPoint[1] - (m_height / 2.0); yRangeMax = m_arcballPoint[1] + (m_height / 2.0); xStart = m_unitWidth * ((int) (xRangeMin / m_unitWidth)); yStart = m_unitWidth * ((int) (yRangeMin / m_unitWidth)); for ( x = xStart; x < xRangeMax; x += m_unitWidth ) { glVertex3f( x, 0, yRangeMin ); glVertex3f( x, 0, yRangeMax ); } for ( y = yStart; y < yRangeMax; y += m_unitWidth ) { glVertex3f( xRangeMin, 0, y ); glVertex3f( xRangeMax, 0, y ); } break; default: log_error( "Unhandled view direction: %d\n", m_viewDirection ); break; } glEnd(); glColor3f( 0.35f, 0.35f, 0.35f ); glRasterPos3f( xRangeMin, yRangeMin, 0.0f ); switch ( m_viewDirection ) { case ViewFront: break; case ViewBack: glRasterPos3f( xRangeMax, yRangeMin, 0.0f ); break; case ViewLeft: glRasterPos3f( 0.0f, yRangeMin, xRangeMax ); break; case ViewRight: glRasterPos3f( 0.0f, yRangeMin, xRangeMin ); break; case ViewTop: glRasterPos3f( xRangeMin, 0.0f, yRangeMax ); break; case ViewBottom: glRasterPos3f( xRangeMin, 0.0f, yRangeMin ); break; default: log_error( "Unhandled view direction: %d\n", m_viewDirection ); break; } g_prefs.setDefault( "ui_render_text", 0 ); if ( g_prefs( "ui_render_text" ).intValue() != 0 ) { // Broken with Qt4 + non-accelerated nVidia card (possibly other configs as // well). That is why it is disabled by default. You can set ui_render_text // to a non-zero value in your mm3drc file to enable text rendering. QString text; text.sprintf( "%g", m_unitWidth ); renderText( 2, this->height() - 12, text, QFont( "Sans", 10 ) ); } } } void ModelViewport::drawOrigin() { glDisable( GL_DEPTH_TEST ); glBegin( GL_LINES ); double scale = m_zoomLevel / 10.0; #ifdef NEWVIEWPORT if ( m_viewDirection == ViewPerspective ) { double x = m_arcballPoint[0]; double y = m_arcballPoint[1]; double z = m_arcballPoint[2] + m_zoomLevel; scale = sqrt( x*x + y*y + z*z ) / 10.0; } #endif // NEWVIEWPORT glColor3f( 1, 0, 0 ); glVertex3f( 0, 0, 0 ); glVertex3f( scale, 0, 0 ); glColor3f( 0, 1, 0 ); glVertex3f( 0, 0, 0 ); glVertex3f( 0, scale, 0 ); glColor3f( 0, 0, 1 ); glVertex3f( 0, 0, 0 ); glVertex3f( 0, 0, scale ); glEnd(); glEnable( GL_DEPTH_TEST ); } void ModelViewport::drawBackground() { glDisable( GL_LIGHTING ); glColor3f( 1.0f, 1.0f, 1.0f ); updateBackground(); if ( m_backgroundFile[0] != '\0' ) { if ( m_viewDirection != ViewPerspective && m_viewDirection != ViewOrtho ) { int index = (int) m_viewDirection - 1; float cenX = 0.0f; float cenY = 0.0f; float cenZ = 0.0f; float minX = 0.0f; float minY = 0.0f; float minZ = 0.0f; float maxX = 0.0f; float maxY = 0.0f; float maxZ = 0.0f; float normX = 0.0f; float normY = 0.0f; float normZ = 0.0f; float w = m_texture->m_origWidth; float h = m_texture->m_origHeight; float dimMax = w > h ? w : h; float scale = m_model->getBackgroundScale( index ); m_model->getBackgroundCenter( index, cenX, cenY, cenZ ); glBindTexture( GL_TEXTURE_2D, m_backgroundTexture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP ); glEnable( GL_TEXTURE_2D ); glBegin( GL_QUADS ); switch ( m_viewDirection ) { case ViewFront: minZ = maxZ = -((m_farOrtho / 2.0f) - 0.1); minX = -scale * (w / dimMax) + cenX; maxX = scale * (w / dimMax) + cenX; minY = -scale * (h / dimMax) + cenY; maxY = scale * (h / dimMax) + cenY; normZ = 1.0f; break; case ViewBack: minZ = maxZ = ((m_farOrtho / 2.0f) - 0.1); minX = scale * (w / dimMax) + cenX; maxX = -scale * (w / dimMax) + cenX; minY = -scale * (h / dimMax) + cenY; maxY = scale * (h / dimMax) + cenY; normZ = -1.0f; break; case ViewRight: minX = maxX = ((m_farOrtho / 2.0f) - 0.1); minZ = -scale * (w / dimMax) + cenZ; maxZ = scale * (w / dimMax) + cenZ; minY = -scale * (h / dimMax) + cenY; maxY = scale * (h / dimMax) + cenY; normX = 1.0f; break; case ViewLeft: minX = maxX = -((m_farOrtho / 2.0f) - 0.1); minZ = scale * (w / dimMax) + cenZ; maxZ = -scale * (w / dimMax) + cenZ; minY = -scale * (h / dimMax) + cenY; maxY = scale * (h / dimMax) + cenY; normX = -1.0f; break; case ViewTop: minY = maxY = -((m_farOrtho / 2.0f) - 0.1); minX = -scale * (w / dimMax) + cenX; maxX = scale * (w / dimMax) + cenX; minZ = scale * (h / dimMax) + cenZ; maxZ = -scale * (h / dimMax) + cenZ; normY = 1.0f; break; case ViewBottom: minY = maxY = ((m_farOrtho / 2.0f) - 0.1); minX = -scale * (w / dimMax) + cenX; maxX = scale * (w / dimMax) + cenX; minZ = -scale * (h / dimMax) + cenZ; maxZ = scale * (h / dimMax) + cenZ; normY = -1.0f; break; default: break; } if ( m_viewDirection == ViewLeft || m_viewDirection == ViewRight ) { glNormal3f( normX, normY, normZ ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( minX, minY, minZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( maxX, maxY, minZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( maxX, maxY, maxZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( minX, minY, maxZ ); } else { glNormal3f( normX, normY, normZ ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( minX, minY, minZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( maxX, minY, minZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( maxX, maxY, maxZ ); glNormal3f( normX, normY, normZ ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( minX, maxY, maxZ ); } glEnd(); } } } void ModelViewport::drawOverlay() { setViewportOverlay(); glDisable( GL_LIGHTING ); glColor3f( 1.0f, 1.0f, 1.0f ); glEnable( GL_TEXTURE_2D ); int w = this->width(); int h = this->height(); /* glVertex3f( w - , h, 0 ); glVertex3f( w - SCROLL_SIZE, h, 0 ); glVertex3f( w - SCROLL_SIZE, h - SCROLL_SIZE, 0 ); glVertex3f( w, h - SCROLL_SIZE, 0 ); glVertex3f( w - SCROLL_ALL_X, h - SCROLL_ALL_Y, 0 ); glVertex3f( w - SCROLL_ALL_X + SCROLL_SIZE, h - SCROLL_ALL_Y, 0 ); glVertex3f( w - SCROLL_ALL_X + SCROLL_SIZE, h - SCROLL_ALL_Y + SCROLL_SIZE, 0 ); glVertex3f( w - SCROLL_ALL_X, h - SCROLL_ALL_Y + SCROLL_SIZE, 0 ); */ int sx = 0; int sy = 0; int size = SCROLL_SIZE; for ( int b = 0; b < ScrollButtonMAX; b++ ) { ScrollButtonT * sbt = &s_buttons[b]; sx = sbt->x; sy = sbt->y; glBindTexture( GL_TEXTURE_2D, m_scrollTextures[ sbt->texIndex ] ); glBegin( GL_QUADS ); glTexCoord2f( sbt->s1, sbt->t1 ); glVertex3f( w + sx, h + sy, 0 ); glTexCoord2f( sbt->s2, sbt->t2 ); glVertex3f( w + sx + size, h + sy, 0 ); glTexCoord2f( sbt->s3, sbt->t3 ); glVertex3f( w + sx + size, h + sy + size, 0 ); glTexCoord2f( sbt->s4, sbt->t4 ); glVertex3f( w + sx, h + sy + size, 0 ); glEnd(); } glDisable( GL_TEXTURE_2D ); } void ModelViewport::makeTextureFromImage( const QImage & i, GLuint & t ) { glBindTexture( GL_TEXTURE_2D, t ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); int w = i.width(); int h = i.height(); unsigned pixelCount = w * i.height(); uint8_t * data = new uint8_t[ pixelCount * 3 ]; for ( int y = 0; y < h; y ++ ) { for ( int x = 0; x < w; x++ ) { QRgb p = i.pixel( x, h - y - 1 ); data[ ((y * w + x)*3) + 0 ] = qRed( p ); data[ ((y * w + x)*3) + 1 ] = qGreen( p ); data[ ((y * w + x)*3) + 2 ] = qBlue( p ); } } gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, w, h, GL_RGB, GL_UNSIGNED_BYTE, data ); delete[] data; } double ModelViewport::getUnitWidth() { if ( m_viewDirection == ViewPerspective || m_viewDirection == ViewOrtho ) { return g_prefs( "ui_3dgrid_inc" ).doubleValue(); } double unitWidth = g_prefs( "ui_grid_inc" ).doubleValue(); double ratio; int scale_min, scale_max; if ( g_prefs.exists( "ui_grid_mode" ) || !g_prefs.exists( "ui_grid_decimal" ) ) { // Note early return for fixed width ('case 2:') switch ( g_prefs( "ui_grid_mode" ).intValue() ) { default: case 0: // Binary ratio = 2.0; scale_min = 4; scale_max = 16; break; case 1: // Decimal ratio = 10.0; scale_min = 2; scale_max = 60; break; case 2: // Fixed return unitWidth; break; } } else { // ui_grid_decimal is set, and ui_grid_mode is not. if ( g_prefs( "ui_grid_decimal" ).intValue() != 0 ) { ratio = 10.0; scale_min = 2; scale_max = 60; g_prefs( "ui_grid_mode" ) = 1; } else { ratio = 2.0; scale_min = 4; scale_max = 16; g_prefs( "ui_grid_mode" ) = 0; } } double maxDimension = (m_width > m_height) ? m_width : m_height; while ( (maxDimension / unitWidth) > scale_max ) { unitWidth *= ratio; } while ( (maxDimension / unitWidth) < scale_min ) { unitWidth /= ratio; } return unitWidth; } void ModelViewport::updateBackground() { int index = (int) m_viewDirection - 1; std::string filename = m_model->getBackgroundImage( index ); if ( strcmp( filename.c_str(), m_backgroundFile.c_str() ) != 0 ) { m_backgroundFile = filename; if ( m_backgroundFile[0] != '\0' ) { m_texture = TextureManager::getInstance()->getTexture( m_backgroundFile.c_str(), false, false ); if ( !m_texture ) { QString str = tr("Could not load background %1").arg( m_backgroundFile.c_str() ); model_status( m_model, StatusError, STATUSTIME_LONG, "%s", (const char *) str.toUtf8() ); m_texture = TextureManager::getInstance()->getDefaultTexture( m_backgroundFile.c_str() ); } glBindTexture( GL_TEXTURE_2D, m_backgroundTexture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); GLuint format = m_texture->m_format == Texture::FORMAT_RGBA ? GL_RGBA : GL_RGB; gluBuild2DMipmaps( GL_TEXTURE_2D, format, m_texture->m_width, m_texture->m_height, format, GL_UNSIGNED_BYTE, m_texture->m_data ); } } } void ModelViewport::adjustViewport() { setViewportDraw(); updateGL(); } void ModelViewport::setViewportDraw() { makeCurrent(); m_inOverlay = false; glViewport( 0, 0, ( GLint ) m_viewportWidth, ( GLint ) m_viewportHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); GLfloat ratio = ( GLfloat ) m_viewportWidth / ( GLfloat ) m_viewportHeight; if ( m_viewDirection == ViewPerspective ) { m_far = m_zoomLevel * 2000.0; m_near = m_zoomLevel * 0.002; gluPerspective( 45.0f, ratio, m_near, m_far ); float x = 0.0; float y = 0.0; if ( m_viewportHeight > m_viewportWidth ) { x = m_zoomLevel; y = x / ratio; } else { y = m_zoomLevel; x = y * ratio; } m_width = x * 2.0; m_height = y * 2.0; } else { float x = 0.0; float y = 0.0; if ( m_viewportHeight > m_viewportWidth ) { x = m_zoomLevel; y = x / ratio; } else { y = m_zoomLevel; x = y * ratio; } #ifdef NEWVIEWPORT glOrtho( m_arcballPoint[0] - x, m_arcballPoint[0] + x, m_arcballPoint[1] - y, m_arcballPoint[1] + y, m_nearOrtho, m_farOrtho ); #else // NEWVIEWPORT glOrtho( m_centerX - x, m_centerX + x, m_centerY - y, m_centerY + y, m_nearOrtho, m_farOrtho ); #endif // NEWVIEWPORT m_width = x * 2.0; m_height = y * 2.0; switch ( m_viewDirection ) { case ViewFront: m_rotX = 0; m_rotY = 0; m_rotZ = 0; break; case ViewBack: m_rotX = 0; m_rotY = 180; m_rotZ = 0; break; case ViewLeft: m_rotX = 0; m_rotY = 90; m_rotZ = 0; break; case ViewRight: m_rotX = 0; m_rotY = -90; m_rotZ = 0; break; case ViewTop: m_rotX = -90; m_rotY = 0; m_rotZ = 0; break; case ViewBottom: m_rotX = 90; m_rotY = 0; m_rotZ = 0; break; default: break; } } m_viewMatrix.loadIdentity(); if ( m_viewDirection == ViewOrtho ) { m_viewMatrix.setRotationInDegrees( m_rotX, m_rotY, m_rotZ ); } else { m_viewMatrix.setRotationInDegrees( -m_rotX, -m_rotY, -m_rotZ ); } #ifdef NEWVIEWPORT m_viewMatrix.setTranslation( -m_arcballPoint[0], -m_arcballPoint[1], -m_arcballPoint[2] ); #else // NEWVIEWPORT m_viewMatrix.setTranslation( -m_centerX, -m_centerY, 0.0 ); #endif // NEWVIEWPORT if ( m_viewDirection == ViewOrtho ) { //m_viewMatrix.setRotationInDegrees( m_arcballPoint[0], m_arcballPoint[1], m_arcballPoint[2] ); } m_invMatrix = m_viewMatrix.getInverse(); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } void ModelViewport::setViewportOverlay() { makeCurrent(); m_inOverlay = true; glViewport( 0, 0, ( GLint ) m_viewportWidth, ( GLint ) m_viewportHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0, this->width(), 0, this->height(), m_nearOrtho, m_farOrtho ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } void ModelViewport::wheelEvent( QWheelEvent * e ) { if ( e->delta() > 0 ) { if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) { rotateClockwise(); } else { zoomIn(); } } else { if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) { rotateCounterClockwise(); } else { zoomOut(); } } } void ModelViewport::zoomIn() { if ( m_activeButton == Qt::NoButton ) { if ( (m_zoomLevel * VP_ZOOMSCALE) > 0.0001 ) { m_zoomLevel *= (VP_ZOOMSCALE); } m_unitWidth = getUnitWidth(); char str[80]; PORT_snprintf( str, sizeof(str), "Units: %g", m_unitWidth ); model_status( m_model, StatusNormal, STATUSTIME_NONE, str ); QString zoomStr; zoomStr.sprintf( "%f", m_zoomLevel ); emit zoomLevelChanged( zoomStr ); makeCurrent(); adjustViewport(); } } void ModelViewport::zoomOut() { if ( m_activeButton == Qt::NoButton ) { if ( (m_zoomLevel / VP_ZOOMSCALE) < 250000 ) { m_zoomLevel /= VP_ZOOMSCALE; } m_unitWidth = getUnitWidth(); char str[80]; PORT_snprintf( str, sizeof(str), "Units: %g", m_unitWidth ); model_status( m_model, StatusNormal, STATUSTIME_NONE, str ); QString zoomStr; zoomStr.sprintf( "%f", m_zoomLevel ); emit zoomLevelChanged( zoomStr ); makeCurrent(); adjustViewport(); } } void ModelViewport::scrollUp() { m_centerY += m_zoomLevel * 0.10f; m_arcballPoint[1] += m_zoomLevel * 0.10f; makeCurrent(); adjustViewport(); } void ModelViewport::scrollDown() { m_centerY -= m_zoomLevel * 0.10f; m_arcballPoint[1] -= m_zoomLevel * 0.10f; makeCurrent(); adjustViewport(); } void ModelViewport::scrollLeft() { m_centerX -= m_zoomLevel * 0.10f; m_arcballPoint[0] -= m_zoomLevel * 0.10f; makeCurrent(); adjustViewport(); } void ModelViewport::scrollRight() { m_centerX += m_zoomLevel * 0.10f; m_arcballPoint[0] += m_zoomLevel * 0.10f; makeCurrent(); adjustViewport(); } void ModelViewport::rotateUp() { rotateViewport( -15.0 * PIOVER180, 0.0 ); makeCurrent(); adjustViewport(); } void ModelViewport::rotateDown() { rotateViewport( 15.0 * PIOVER180, 0.0 ); makeCurrent(); adjustViewport(); } void ModelViewport::rotateLeft() { rotateViewport( 0.0, -15.0 * PIOVER180 ); makeCurrent(); adjustViewport(); } void ModelViewport::rotateRight() { rotateViewport( 0.0, 15.0 * PIOVER180 ); makeCurrent(); adjustViewport(); } void ModelViewport::rotateClockwise() { rotateViewport( 0.0, 0.0, -15.0 * PIOVER180 ); makeCurrent(); adjustViewport(); } void ModelViewport::rotateCounterClockwise() { rotateViewport( 0.0, 0.0, 15.0 * PIOVER180 ); makeCurrent(); adjustViewport(); } void ModelViewport::mousePressEvent( QMouseEvent * e ) { //printf( "press = %d\n", e->button() ); if ( m_activeButton != Qt::NoButton ) { e->ignore(); return; } e->accept(); m_activeButton = e->button(); m_operation = MO_None; int w = this->width(); int h = this->height(); int bx = e->pos().x(); int by = h - e->pos().y(); m_overlayButton = ScrollButtonMAX; int sx = 0; int sy = 0; int size = SCROLL_SIZE; for ( int b = 0; m_overlayButton == ScrollButtonMAX && b < ScrollButtonMAX; b++ ) { sx = s_buttons[b].x; sy = s_buttons[b].y; if ( (bx >= w + sx) && (bx <= w + sx + size) && (by >= h + sy) && (by <= h + sy + size) ) { m_overlayButton = (ScrollButtonE) b; if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) { m_operation = ( m_overlayButton == ScrollButtonPan ) ? MO_Rotate : MO_RotateButton; } else { m_operation = ( m_overlayButton == ScrollButtonPan ) ? MO_Pan : MO_PanButton; } switch ( m_overlayButton ) { case ScrollButtonPan: m_scrollStartPosition = e->pos(); break; case ScrollButtonUp: if ( m_operation == MO_RotateButton ) rotateUp(); else scrollUp(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonDown: if ( m_operation == MO_RotateButton ) rotateDown(); else scrollDown(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonLeft: if ( m_operation == MO_RotateButton ) rotateLeft(); else scrollLeft(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonRight: if ( m_operation == MO_RotateButton ) rotateRight(); else scrollRight(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; default: break; } } } if ( m_operation == MO_None ) { if ( e->button() == Qt::MidButton ) { m_operation = MO_Pan; m_scrollStartPosition = e->pos(); } else if ( (m_viewDirection == ViewPerspective && e->button() == Qt::LeftButton) || (e->modifiers() & Qt::ControlModifier) ) { m_operation = MO_Rotate; m_scrollStartPosition = e->pos(); } else if ( m_viewDirection != ViewPerspective ) { m_operation = MO_Tool; int button = constructButtonState( e ); ::Tool * tool = m_toolbox->getCurrentTool(); tool->mouseButtonDown( this, button, e->pos().x(), e->pos().y() ); } } /* if ( m_overlayButton == ScrollButtonMAX ) { if ( e->button() == Qt::MidButton || (m_viewDirection == ViewPerspective && e->button() == Qt::LeftButton) ) { m_scrollStartPosition = e->pos(); } else { int button = constructButtonState( e ); ::Tool * tool = m_toolbox->getCurrentTool(); tool->mouseButtonDown( this, button, e->pos().x(), e->pos().y() ); } } */ } void ModelViewport::mouseReleaseEvent( QMouseEvent * e ) { //printf( "release = %d\n", e->button() ); if ( e->button() == m_activeButton ) { if ( m_overlayButton == ScrollButtonMAX ) { e->accept(); if ( m_operation == MO_Tool ) { int button = constructButtonState( e ); ::Tool * tool = m_toolbox->getCurrentTool(); tool->mouseButtonUp( this, button, e->pos().x(), e->pos().y() ); m_model->operationComplete( tool->getName( 0 ) ); if ( m_model->getSelectedProjectionCount() > 0 ) { m_model->setDrawProjections( true ); updateView(); } if ( m_model->getSelectedBoneJointCount() > 0 ) { Model::DrawJointModeE mode = static_cast( g_prefs( "ui_draw_joints" ).intValue() ); if ( mode == Model::JOINTMODE_NONE ) mode = Model::JOINTMODE_BONES; m_model->setDrawJoints( mode ); updateView(); } } } else { m_overlayButton = ScrollButtonMAX; m_scrollTimer->stop(); model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Use the middle mouse button to drag/pan the viewport").toUtf8() ); } m_activeButton = Qt::NoButton; m_operation = MO_None; } } void ModelViewport::mouseMoveEvent( QMouseEvent * e ) { e->accept(); if ( ! this->hasFocus() ) { this->setFocus(); } if ( m_viewDirection != ViewPerspective ) { int x = e->pos().x(); int y = e->pos().y(); /* double xcoord = 0.0; double ycoord = 0.0; double zcoord = 0.0; getXValue( x, y, &xcoord ); getYValue( x, y, &ycoord ); getZValue( x, y, &zcoord ); */ Vector pos; getParentXYValue( x, y, pos[0], pos[1], true ); m_invMatrix.apply( pos ); for ( int i = 0; i < 3; i++ ) { if ( fabs(pos[i]) < 0.000001 ) pos[i] = 0.0; } char str[80]; PORT_snprintf( str, sizeof(str), "Units: %g (%g, %g, %g)", m_unitWidth, pos[0], pos[1], pos[2] ); model_status( m_model, StatusNormal, STATUSTIME_NONE, str ); } else { model_status( m_model, StatusNormal, STATUSTIME_NONE, "Units: %g", getUnitWidth()); } if ( m_operation == MO_Rotate ) { QPoint curPos = e->pos(); double xDiff = -(m_scrollStartPosition.x() - curPos.x()); double yDiff = -(m_scrollStartPosition.y() - curPos.y()); double rotY = (double) xDiff / (double) this->width() * 3.14159 * 2.0; double rotX = (double) yDiff / (double) this->height() * 3.14159 * 2.0; rotateViewport( rotX, rotY ); m_scrollStartPosition = curPos; } else if ( m_operation == MO_Pan ) { #ifdef NEWVIEWPORT //printf( "adjusting translation\n" ); QPoint curPos = e->pos(); double xDiff = m_scrollStartPosition.x() - curPos.x(); xDiff = xDiff * (m_width / m_viewportWidth); m_centerX += xDiff; double yDiff = m_scrollStartPosition.y() - curPos.y(); yDiff = -yDiff; // Adjust for difference between pixel and GL coordinates yDiff = yDiff * (m_height / m_viewportHeight); m_centerY += yDiff; //m_viewMatrix.inverseRotateVector( vec ); m_arcballPoint[0] += xDiff; m_arcballPoint[1] += yDiff; /* double vec[3]; vec[0] = xDiff; vec[1] = yDiff; vec[2] = 0.0; vec[0] = m_arcballPoint[0]; vec[1] = m_arcballPoint[1]; vec[2] = m_arcballPoint[2]; m_viewMatrix.inverseRotateVector( vec ); log_debug( "World coords = %f,%f,%f\n", vec[0], vec[1], vec[2] ); */ m_scrollStartPosition = curPos; #else //printf( "adjusting translation\n" ); QPoint curPos = e->pos(); double xDiff = m_scrollStartPosition.x() - curPos.x(); m_centerX += xDiff * (m_width / m_viewportWidth); double yDiff = m_scrollStartPosition.y() - curPos.y(); yDiff = -yDiff; // Adjust for difference between pixel and GL coordinates m_centerY += yDiff * (m_height / m_viewportHeight); m_scrollStartPosition = curPos; #endif // NEWVIEWPORT makeCurrent(); adjustViewport(); } else if ( m_operation == MO_Tool ) { //printf( "tool mouse event\n" ); int button = constructButtonState( e ); ::Tool * tool = m_toolbox->getCurrentTool(); tool->mouseButtonMove( this, button, e->pos().x(), e->pos().y() ); } #if 0 if ( m_overlayButton == ScrollButtonMAX ) { if ( m_activeButton ) { if ( m_activeButton == Qt::MidButton || (m_viewDirection == ViewPerspective && m_activeButton == Qt::LeftButton) ) { if ( m_viewDirection == ViewPerspective && (m_activeButton == Qt::LeftButton) ) { QPoint curPos = e->pos(); double xDiff = -(m_scrollStartPosition.x() - curPos.x()); double yDiff = -(m_scrollStartPosition.y() - curPos.y()); Matrix mcur; Matrix mcurinv; double rot[3]; rot[0] = m_rotX * PIOVER180; rot[1] = m_rotY * PIOVER180; rot[2] = m_rotZ * PIOVER180; mcur.setRotation( rot ); mcurinv = mcur.getInverse(); #ifdef NEWVIEWPORT mcur.inverseRotateVector( m_arcballPoint ); #endif // NEWVIEWPORT Vector yvec; yvec.set( 0, 0.0 ); yvec.set( 1, 1.0 ); yvec.set( 2, 0.0 ); yvec.set( 3, 0.0 ); Vector xvec; xvec.set( 0, 1.0 ); xvec.set( 1, 0.0 ); xvec.set( 2, 0.0 ); xvec.set( 3, 0.0 ); Matrix mx; Matrix my; double rotY = (double) xDiff / (double) this->width() * 3.14159 * 2.0; double rotX = (double) yDiff / (double) this->height() * 3.14159 * 2.0; yvec = yvec * mcurinv; my.setRotationOnAxis( yvec.getVector(), rotY ); xvec = xvec * mcurinv; mx.setRotationOnAxis( xvec.getVector(), rotX ); mcur = mx * mcur; mcur = my * mcur; mcur.getRotation( rot ); m_rotX = rot[0] / PIOVER180; m_rotY = rot[1] / PIOVER180; m_rotZ = rot[2] / PIOVER180; //m_rotY += xDiff * PIOVER180 * 14.0; //m_rotX += yDiff * PIOVER180 * 14.0; #ifdef NEWVIEWPORT mcur.apply3( m_arcballPoint ); #endif // NEWVIEWPORT m_scrollStartPosition = curPos; // And finally, update the view makeCurrent(); adjustViewport(); } else { #ifdef NEWVIEWPORT //printf( "adjusting translation\n" ); QPoint curPos = e->pos(); double xDiff = m_scrollStartPosition.x() - curPos.x(); xDiff = xDiff * (m_width / m_viewportWidth); m_centerX += xDiff; double yDiff = m_scrollStartPosition.y() - curPos.y(); yDiff = -yDiff; // Adjust for difference between pixel and GL coordinates yDiff = yDiff * (m_height / m_viewportHeight); m_centerY += yDiff; //m_viewMatrix.inverseRotateVector( vec ); m_arcballPoint[0] += xDiff; m_arcballPoint[1] += yDiff; /* double vec[3]; vec[0] = xDiff; vec[1] = yDiff; vec[2] = 0.0; vec[0] = m_arcballPoint[0]; vec[1] = m_arcballPoint[1]; vec[2] = m_arcballPoint[2]; m_viewMatrix.inverseRotateVector( vec ); log_debug( "World coords = %f,%f,%f\n", vec[0], vec[1], vec[2] ); */ m_scrollStartPosition = curPos; #else //printf( "adjusting translation\n" ); QPoint curPos = e->pos(); double xDiff = m_scrollStartPosition.x() - curPos.x(); m_centerX += xDiff * (m_width / m_viewportWidth); double yDiff = m_scrollStartPosition.y() - curPos.y(); yDiff = -yDiff; // Adjust for difference between pixel and GL coordinates m_centerY += yDiff * (m_height / m_viewportHeight); m_scrollStartPosition = curPos; #endif // NEWVIEWPORT makeCurrent(); adjustViewport(); } } else { //printf( "tool mouse event\n" ); int button = constructButtonState( e ); ::Tool * tool = m_toolbox->getCurrentTool(); tool->mouseButtonMove( this, button, e->pos().x(), e->pos().y() ); } } } else { if ( m_overlayButton == ScrollButtonPan ) { //printf( "adjusting translation\n" ); QPoint curPos = e->pos(); double xDiff = m_scrollStartPosition.x() - curPos.x(); xDiff = xDiff * (m_width / m_viewportWidth); m_centerX += xDiff; double yDiff = m_scrollStartPosition.y() - curPos.y(); yDiff = -yDiff; // Adjust for difference between pixel and GL coordinates yDiff = yDiff * (m_height / m_viewportHeight); m_centerY += yDiff; m_arcballPoint[0] += xDiff; m_arcballPoint[1] += yDiff; m_scrollStartPosition = curPos; makeCurrent(); adjustViewport(); } } #endif // 0 } void ModelViewport::keyPressEvent( QKeyEvent * e ) { if ( m_activeButton == Qt::NoButton ) { switch ( e->key() ) { case Qt::Key_Equal: case Qt::Key_Plus: { if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) { rotateClockwise(); } else { zoomIn(); } } break; case Qt::Key_Minus: case Qt::Key_Underscore: { if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) { rotateCounterClockwise(); } else { zoomOut(); } } break; case Qt::Key_QuoteLeft: { int newDir = 0; switch ( m_viewDirection ) { case ViewPerspective: newDir = ViewOrtho; break; case ViewFront: case ViewBack: case ViewRight: case ViewLeft: case ViewTop: case ViewBottom: case ViewOrtho: newDir = ViewPerspective; break; default: break; } emit viewDirectionChanged( newDir ); } break; case Qt::Key_Backslash: { int newDir = 0; switch ( m_viewDirection ) { case ViewFront: newDir = ViewBack; break; case ViewBack: newDir = ViewFront; break; case ViewRight: newDir = ViewLeft; break; case ViewLeft: newDir = ViewRight; break; case ViewTop: newDir = ViewBottom; break; case ViewBottom: newDir = ViewTop; break; case ViewPerspective: newDir = ViewOrtho; break; case ViewOrtho: newDir = ViewPerspective; break; default: break; } emit viewDirectionChanged( newDir ); } break; case Qt::Key_0: m_centerX = 0.0; m_centerY = 0.0; m_arcballPoint[0] = 0.0; m_arcballPoint[1] = 0.0; m_arcballPoint[2] = 0.0; makeCurrent(); adjustViewport(); break; case Qt::Key_Up: if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) rotateUp(); else scrollUp(); break; case Qt::Key_Down: if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) rotateDown(); else scrollDown(); break; case Qt::Key_Left: if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) rotateLeft(); else scrollLeft(); break; case Qt::Key_Right: if ( (e->modifiers() & Qt::ControlModifier) == Qt::ControlModifier ) rotateRight(); else scrollRight(); break; case Qt::Key_1: case Qt::Key_2: case Qt::Key_3: case Qt::Key_4: case Qt::Key_5: case Qt::Key_6: case Qt::Key_7: case Qt::Key_8: case Qt::Key_9: if ( e->modifiers() & Qt::ControlModifier ) { log_debug( "set viewport %d\n", e->key() - Qt::Key_1 ); int slot = ( (int) e->key() - (int) Qt::Key_1 ); ViewStateT viewState; viewState.direction = m_viewDirection; viewState.zoom = m_zoomLevel; viewState.rotation[0] = m_rotX; viewState.rotation[1] = m_rotY; viewState.rotation[2] = m_rotZ; viewState.translation[0] = m_arcballPoint[0]; viewState.translation[1] = m_arcballPoint[1]; viewState.translation[2] = m_arcballPoint[2]; emit viewportSaveState( slot, viewState ); } else { log_debug( "viewport recall %d\n", e->key() - Qt::Key_1 ); int slot = ( (int) e->key() - (int) Qt::Key_1 ); emit viewportRecallState( slot ); return; } break; default: QGLWidget::keyPressEvent( e ); return; break; } } e->accept(); } void ModelViewport::rotateViewport( double rotX, double rotY, double rotZ ) { if ( fabs( rotX ) >0.00001 || fabs( rotY ) > 0.00001 || fabs( rotZ ) > 0.00001 ) { if ( m_viewDirection != ViewPerspective && m_viewDirection != ViewOrtho ) { emit viewDirectionChanged( ViewOrtho ); } Matrix mcur; Matrix mcurinv; double rot[3]; rot[0] = m_rotX * PIOVER180; rot[1] = m_rotY * PIOVER180; rot[2] = m_rotZ * PIOVER180; mcur.setRotation( rot ); mcurinv = mcur.getInverse(); #ifdef NEWVIEWPORT mcur.inverseRotateVector( m_arcballPoint ); #endif // NEWVIEWPORT Vector yvec; yvec.set( 0, 0.0 ); yvec.set( 1, 1.0 ); yvec.set( 2, 0.0 ); yvec.set( 3, 0.0 ); Vector xvec; xvec.set( 0, 1.0 ); xvec.set( 1, 0.0 ); xvec.set( 2, 0.0 ); xvec.set( 3, 0.0 ); Vector zvec; zvec.set( 0, 0.0 ); zvec.set( 1, 0.0 ); zvec.set( 2, 1.0 ); zvec.set( 3, 0.0 ); Matrix mx; Matrix my; Matrix mz; zvec = zvec * mcurinv; mz.setRotationOnAxis( zvec.getVector(), rotZ ); yvec = yvec * mcurinv; my.setRotationOnAxis( yvec.getVector(), rotY ); xvec = xvec * mcurinv; mx.setRotationOnAxis( xvec.getVector(), rotX ); mcur = mx * mcur; mcur = my * mcur; mcur = mz * mcur; mcur.getRotation( rot ); m_rotX = rot[0] / PIOVER180; m_rotY = rot[1] / PIOVER180; m_rotZ = rot[2] / PIOVER180; //m_rotY += xDiff * PIOVER180 * 14.0; //m_rotX += yDiff * PIOVER180 * 14.0; #ifdef NEWVIEWPORT mcur.apply3( m_arcballPoint ); #endif // NEWVIEWPORT // And finally, update the view makeCurrent(); adjustViewport(); } } void ModelViewport::setViewState( const ViewStateT & viewState ) { m_viewDirection = viewState.direction; m_zoomLevel = viewState.zoom; m_rotX = viewState.rotation[0]; m_rotY = viewState.rotation[1]; m_rotZ = viewState.rotation[2]; m_arcballPoint[0] = viewState.translation[0]; m_arcballPoint[1] = viewState.translation[1]; m_arcballPoint[2] = viewState.translation[2]; makeCurrent(); adjustViewport(); } void ModelViewport::viewChangeEvent( int dir ) { log_debug( "viewChangeEvent( %d )\n", dir ); if ( dir == m_viewDirection ) { return; } if ( m_viewDirection == ViewPerspective ) //|| m_viewDirection == ViewOrtho ) { Matrix m; m.setRotationInDegrees( 0.0f, 0.0f, -m_rotZ ); m.apply3( m_arcballPoint ); m.setRotationInDegrees( 0.0f, -m_rotY, 0.0f ); m.apply3( m_arcballPoint ); m.setRotationInDegrees( -m_rotX, 0.0f, 0.0f ); m.apply3( m_arcballPoint ); } else { m_invMatrix.apply3( m_arcballPoint ); } log_debug( "center point = %f,%f,%f\n", m_arcballPoint[0], m_arcballPoint[1], m_arcballPoint[2] ); bool toFree = false; switch ( m_viewDirection ) { case ViewFront: case ViewBack: case ViewRight: case ViewLeft: case ViewTop: case ViewBottom: if ( dir == ViewPerspective || dir == ViewOrtho ) { toFree = true; } break; default: break; } if ( toFree ) { log_debug( "inverting rotation\n" ); m_rotX = -m_rotX; m_rotY = -m_rotY; m_rotZ = -m_rotZ; } else { switch ( dir ) { case ViewFront: m_rotX = 0; m_rotY = 0; m_rotZ = 0; break; case ViewBack: m_rotX = 0; m_rotY = 180; m_rotZ = 0; break; case ViewLeft: m_rotX = 0; m_rotY = 90; m_rotZ = 0; break; case ViewRight: m_rotX = 0; m_rotY = -90; m_rotZ = 0; break; case ViewTop: m_rotX = -90; m_rotY = 0; m_rotZ = 0; break; case ViewBottom: m_rotX = 90; m_rotY = 0; m_rotZ = 0; break; default: break; } } Matrix m; m.loadIdentity(); if ( false || (m_viewDirection == ViewPerspective && dir == ViewOrtho) || (m_viewDirection == ViewOrtho && dir == ViewPerspective) ) { m.setRotationInDegrees( m_rotX, m_rotY, m_rotZ ); } else { m.setRotationInDegrees( -m_rotX, -m_rotY, -m_rotZ ); } if ( toFree ) { m = m.getInverse(); } m.apply3( m_arcballPoint ); log_debug( "after point = %f,%f,%f\n", m_arcballPoint[0], m_arcballPoint[1], m_arcballPoint[2] ); m_viewDirection = static_cast( dir ); makeCurrent(); adjustViewport(); } void ModelViewport::setZoomLevel( double zoom ) { if ( m_activeButton == Qt::NoButton ) { m_zoomLevel = zoom; makeCurrent(); adjustViewport(); QString zoomStr; zoomStr.sprintf( "%f", m_zoomLevel ); emit zoomLevelChanged( zoomStr ); } } void ModelViewport::scrollTimeout() { if ( m_operation == MO_RotateButton ) { switch ( m_overlayButton ) { case ScrollButtonUp: rotateUp(); break; case ScrollButtonDown: rotateDown(); break; case ScrollButtonLeft: rotateLeft(); break; case ScrollButtonRight: rotateRight(); break; default: m_scrollTimer->stop(); return; } } else { switch ( m_overlayButton ) { case ScrollButtonUp: scrollUp(); break; case ScrollButtonDown: scrollDown(); break; case ScrollButtonLeft: scrollLeft(); break; case ScrollButtonRight: scrollRight(); break; default: m_scrollTimer->stop(); return; } } m_scrollTimer->setSingleShot( false ); m_scrollTimer->start( 100 ); } void ModelViewport::focusInEvent( QFocusEvent * e ) { m_backColor.setRgb( 150, 210, 210 ); makeCurrent(); glClearColor( m_backColor.red() / 256.0, m_backColor.green() / 256.0, m_backColor.blue() / 256.0, 1.0f ); updateGL(); } void ModelViewport::focusOutEvent( QFocusEvent * e ) { m_backColor.setRgb( 130, 200, 200 ); makeCurrent(); glClearColor( m_backColor.red() / 256.0, m_backColor.green() / 256.0, m_backColor.blue() / 256.0, 1.0f ); updateGL(); } /* void ModelViewport::dragEnterEvent( QDragMoveEvent * e ) { log_debug( "got drag enter event\n" ); if ( QUriDrag::canDecode( e ) ) { log_debug( "is URI\n" ); } if ( QTextDrag::canDecode( e ) ) { log_debug( "is Text\n" ); } if ( QImageDrag::canDecode( e ) ) { log_debug( "is Image\n" ); } //e->accept( QRect( 0, 0, this->width(), this->height() ) ); } */ void ModelViewport::getParentXYValue( int x, int y, double & xval, double & yval, bool selected ) { xval = (((double) x / (double) m_viewportWidth) * m_width) - (m_width / 2.0); yval = (((double) -y / (double) m_viewportHeight) * m_height) + (m_height / 2.0); double maxDist = (4.1 / (double) m_viewportWidth) * m_width; if ( g_prefs.exists( "ui_snap_vertex" ) && g_prefs( "ui_snap_vertex" ).intValue() != 0 ) { // snap to vertex double curDist = maxDist; int curIndex = -1; Model::PositionTypeE curType = Model::PT_Vertex; const Matrix & mat = getParentViewMatrix(); double coord[3] = { 0, 0, 0 }; double saveCoord[3] = { 0, 0, 0 }; size_t vcount = m_model->getVertexCount(); for ( size_t v = 0; v < vcount; v++ ) { if ( selected || !m_model->isVertexSelected( v ) ) { m_model->getVertexCoords( v, coord ); mat.apply3( coord ); coord[0] += mat.get(3,0); coord[1] += mat.get(3,1); coord[2] += mat.get(3,2); double xdiff = coord[0] - xval; double ydiff = coord[1] - yval; double diff = sqrt( xdiff*xdiff + ydiff*ydiff ); if ( diff < curDist ) { curDist = diff; curIndex = v; curType = Model::PT_Vertex; saveCoord[0] = coord[0]; saveCoord[1] = coord[1]; saveCoord[2] = coord[2]; } } } size_t bcount = m_model->getBoneJointCount(); for ( size_t b = 0; b < bcount; b++ ) { if ( selected || !m_model->isBoneJointSelected( b ) ) { m_model->getBoneJointCoords( b, coord ); mat.apply3( coord ); coord[0] += mat.get(3,0); coord[1] += mat.get(3,1); coord[2] += mat.get(3,2); double xdiff = coord[0] - xval; double ydiff = coord[1] - yval; double diff = sqrt( xdiff*xdiff + ydiff*ydiff ); if ( diff < curDist ) { curDist = diff; curIndex = b; curType = Model::PT_Joint; saveCoord[0] = coord[0]; saveCoord[1] = coord[1]; saveCoord[2] = coord[2]; } } } size_t p; size_t pcount = m_model->getPointCount(); for ( p = 0; p < pcount; p++ ) { if ( selected || !m_model->isPointSelected( p ) ) { m_model->getPointCoords( p, coord ); mat.apply3( coord ); coord[0] += mat.get(3,0); coord[1] += mat.get(3,1); coord[2] += mat.get(3,2); double xdiff = coord[0] - xval; double ydiff = coord[1] - yval; double diff = sqrt( xdiff*xdiff + ydiff*ydiff ); if ( diff < curDist ) { curDist = diff; curIndex = p; curType = Model::PT_Point; saveCoord[0] = coord[0]; saveCoord[1] = coord[1]; saveCoord[2] = coord[2]; } } } pcount = m_model->getProjectionCount(); for ( p = 0; p < pcount; p++ ) { if ( selected || !m_model->isProjectionSelected( p ) ) { m_model->getProjectionCoords( p, coord ); mat.apply3( coord ); coord[0] += mat.get(3,0); coord[1] += mat.get(3,1); coord[2] += mat.get(3,2); double xdiff = coord[0] - xval; double ydiff = coord[1] - yval; double diff = sqrt( xdiff*xdiff + ydiff*ydiff ); if ( diff < curDist ) { curDist = diff; curIndex = p; curType = Model::PT_Projection; saveCoord[0] = coord[0]; saveCoord[1] = coord[1]; saveCoord[2] = coord[2]; } } } if ( curIndex >= 0 ) { xval = saveCoord[0]; yval = saveCoord[1]; maxDist = 0.0; } } if ( m_viewDirection != ViewOrtho && g_prefs.exists( "ui_snap_grid" ) && g_prefs( "ui_snap_grid" ).intValue() != 0 ) { // snap to grid double val; int mult; double fudge; fudge = 0.5; #ifdef NEWVIEWPORT double x = xval + m_arcballPoint[0]; #else // NEWVIEWPORT double x = xval + m_centerX; #endif // NEWVIEWPORT if ( x < 0.0 ) { fudge = -0.5; } mult = (int) (x / m_unitWidth + fudge); val = (double) mult * m_unitWidth; if ( fabs( x - val ) < maxDist ) { #ifdef NEWVIEWPORT xval = val - m_arcballPoint[0]; #else // NEWVIEWPORT xval = val - m_centerX; #endif // NEWVIEWPORT } fudge = 0.5; #ifdef NEWVIEWPORT double y = yval + m_arcballPoint[1]; #else // NEWVIEWPORT double y = yval + m_centerY; #endif // NEWVIEWPORT if ( y < 0.0 ) { fudge = -0.5; } mult = (int) (y / m_unitWidth + fudge); val = (double) mult * m_unitWidth; if ( fabs( y - val ) < maxDist ) { #ifdef NEWVIEWPORT yval = val - m_arcballPoint[1]; #else // NEWVIEWPORT yval = val - m_centerY; #endif // NEWVIEWPORT } } } void ModelViewport::getRawParentXYValue( int x, int y, double & xval, double & yval ) { xval = (((double) x / (double) m_viewportWidth) * m_width) - (m_width / 2.0); yval = (((double) -y / (double) m_viewportHeight) * m_height) + (m_height / 2.0); } #ifdef NEWVIEWPORT bool ModelViewport::getXValue( int x, int y, double * val ) { Vector vec; vec[0] = (((double) x / (double) m_viewportWidth) * m_width) - (m_width / 2.0); vec[1] = -((((double) y / (double) m_viewportHeight) * m_height) - (m_height / 2.0)); vec[2] = 0.0; m_invMatrix.apply( vec ); *val = vec[0]; switch ( m_viewDirection ) { case ViewFront: case ViewTop: case ViewBottom: case ViewBack: case ViewOrtho: return true; default: break; } return false; } bool ModelViewport::getYValue( int x, int y, double * val ) { Vector vec; vec[0] = (((double) x / (double) m_viewportWidth) * m_width) - (m_width / 2.0); vec[1] = -((((double) y / (double) m_viewportHeight) * m_height) - (m_height / 2.0)); vec[2] = 0.0; m_invMatrix.apply( vec ); *val = vec[1]; switch ( m_viewDirection ) { case ViewFront: case ViewBack: case ViewLeft: case ViewRight: case ViewOrtho: return true; default: break; } return false; } bool ModelViewport::getZValue( int x, int y, double * val ) { Vector vec; vec[0] = (((double) x / (double) m_viewportWidth) * m_width) - (m_width / 2.0); vec[1] = -((((double) y / (double) m_viewportHeight) * m_height) - (m_height / 2.0)); vec[2] = 0.0; m_invMatrix.apply( vec ); *val = vec[2]; switch ( m_viewDirection ) { case ViewLeft: case ViewRight: case ViewTop: case ViewBottom: case ViewOrtho: return true; default: break; } return false; } #else // NEWVIEWPORT bool ModelViewport::getXValue( int x, int y, double * val ) { switch ( m_viewDirection ) { case ViewFront: case ViewTop: case ViewBottom: *val = (m_centerX - (m_width / 2.0)) + (((double) x / (double) m_viewportWidth) * m_width); break; case ViewBack: *val = ((-m_centerX) + (m_width / 2.0)) + (((double) (-x) / (double) m_viewportWidth) * m_width); break; case ViewRight: case ViewLeft: default: return false; } return true; } bool ModelViewport::getYValue( int x, int y, double * val ) { switch ( m_viewDirection ) { case ViewFront: case ViewBack: case ViewRight: case ViewLeft: *val = (m_centerY + (m_height / 2.0)) - (((double) y / (double) m_viewportHeight) * m_height); break; case ViewTop: case ViewBottom: default: return false; break; } return true; } bool ModelViewport::getZValue( int x, int y, double * val ) { switch ( m_viewDirection ) { case ViewTop: *val = ((-m_centerY) - (m_height / 2.0)) - (((double) (-y) / (double) m_viewportHeight) * m_height); break; case ViewBottom: *val = (m_centerY + (m_height / 2.0)) - (((double) y / (double) m_viewportHeight) * m_height); //*val = (m_centerY + (m_height / 2.0)) - (((double) y / (double) m_viewportHeight) * m_height); break; case ViewRight: *val = (m_centerX - (m_width / 2.0)) + (((double) x / (double) m_viewportWidth) * m_width); break; case ViewLeft: *val = ((-m_centerX) + (m_width / 2.0)) + (((double) (-x) / (double) m_viewportWidth) * m_width); break; case ViewFront: case ViewBack: default: return false; } return true; } #endif // NEWVIEWPORT int ModelViewport::constructButtonState( QMouseEvent * e ) { int button = 0; //switch ( e->button() ) switch ( m_activeButton ) { case Qt::LeftButton: button = ::Tool::BS_Left; break; case Qt::MidButton: button = ::Tool::BS_Middle; break; case Qt::RightButton: button = ::Tool::BS_Right; break; default: break; } if ( e->modifiers() & Qt::ShiftModifier ) { button |= ::Tool::BS_Shift; } if ( e->modifiers() & Qt::AltModifier ) { button |= ::Tool::BS_Alt; } if ( e->modifiers() & Qt::ControlModifier ) { button |= ::Tool::BS_Ctrl; } return button; } void ModelViewport::updateView() { updateGL(); StatusObject * bar = model_status_get_object( m_model ); bar->setVertices( m_model->getVertexCount(), m_model->getSelectedVertexCount() ); bar->setFaces( m_model->getTriangleCount(), m_model->getSelectedTriangleCount() ); bar->setGroups( m_model->getGroupCount() ); bar->setBoneJoints( m_model->getBoneJointCount(), m_model->getSelectedBoneJointCount() ); bar->setPoints( m_model->getPointCount(), m_model->getSelectedPointCount() ); bar->setTextures( m_model->getTextureCount() ); } void ModelViewport::update3dView() { if ( m_viewDirection == ViewPerspective ) { updateView(); } } void ModelViewport::addDecal( Decal * decal ) { m_decals.push_back( decal ); updateGL(); } void ModelViewport::removeDecal( Decal * decal ) { m_decals.remove( decal ); updateGL(); } void ModelViewport::frameArea( double x1, double y1, double z1, double x2, double y2, double z2 ) { double centerX = (x1 + x2) / 2.0; double centerY = (y1 + y2) / 2.0; double centerZ = (z1 + z2) / 2.0; double width = fabs( x1 - x2 ); double height = fabs( y1 - y2 ); double depth = fabs( z1 - z2 ); if ( width < 0.0001667 ) { width = 0.0001667; } if ( height < 0.0001667 ) { height = 0.0001667; } if ( depth < 0.0001667 ) { depth = 0.0001667; } width *= 1.20; height *= 1.20; depth *= 1.20; Vector bounds; bounds[0] = width; bounds[1] = height; bounds[2] = depth; double viewWidth = 0.0; double viewHeight = 0.0; switch ( m_viewDirection ) { #ifdef NEWVIEWPORT case ViewFront: case ViewBack: case ViewRight: case ViewLeft: case ViewTop: case ViewBottom: case ViewOrtho: case ViewPerspective: { m_arcballPoint[0] = centerX; m_arcballPoint[1] = centerY; m_arcballPoint[2] = centerZ; //log_debug( "view = %d (%f,%f,%f)\n", // (int) m_viewDirection, // m_rotX, m_rotY, m_rotZ ); double rx = m_rotX; double ry = m_rotY; double rz = m_rotZ; if ( m_viewDirection != ViewPerspective || m_viewDirection == ViewOrtho ) { rx = -rx; ry = -ry; rz = -rz; } //m_viewMatrix.apply3( m_arcballPoint ); if ( m_viewDirection == ViewOrtho ) { Matrix m; m_viewMatrix.apply3( m_arcballPoint ); m_viewMatrix.apply3( bounds ); /* m.setRotationInDegrees( rx, 0.0f, 0.0f ); m.apply3( m_arcballPoint ); m.apply3( bounds ); m.setRotationInDegrees( 0.0f, ry, 0.0f ); m.apply3( m_arcballPoint ); m.apply3( bounds ); m.setRotationInDegrees( 0.0f, 0.0f, rz ); m.apply3( m_arcballPoint ); m.apply3( bounds ); */ } else { Matrix m; m.setRotationInDegrees( rx, 0.0f, 0.0f ); m.apply3( m_arcballPoint ); m.apply3( bounds ); m.setRotationInDegrees( 0.0f, ry, 0.0f ); m.apply3( m_arcballPoint ); m.apply3( bounds ); m.setRotationInDegrees( 0.0f, 0.0f, rz ); m.apply3( m_arcballPoint ); m.apply3( bounds ); } if ( m_viewDirection == ViewPerspective || m_viewDirection == ViewOrtho ) { viewWidth = viewHeight = sqrt( height*height + width*width + depth*depth ) * 1.2; } else { viewWidth = fabs( bounds[0] ); viewHeight = fabs( bounds[1] ); } //log_debug( "point = %d (%f,%f,%f)\n", // (int) m_viewDirection, // m_arcballPoint[0], m_arcballPoint[1], m_arcballPoint[2] ); } break; default: return; break; #else // NEWVIEWPORT case ViewFront: m_centerX = centerX; m_centerY = centerY; viewWidth = width; viewHeight = height; break; case ViewBack: m_centerX = -centerX; m_centerY = centerY; viewWidth = width; viewHeight = height; break; case ViewRight: m_centerX = centerZ; m_centerY = centerY; viewWidth = depth; viewHeight = height; break; case ViewLeft: m_centerX = -centerZ; m_centerY = centerY; viewWidth = depth; viewHeight = height; break; case ViewTop: m_centerX = centerX; m_centerY = -centerZ; viewWidth = width; viewHeight = depth; break; case ViewBottom: m_centerX = centerX; m_centerY = centerZ; viewWidth = width; viewHeight = depth; break; case ViewPerspective: { double rotation[3]; rotation[0] = m_rotX * PIOVER180; rotation[1] = m_rotY * PIOVER180; rotation[2] = m_rotZ * PIOVER180; Matrix m; m.setRotation( rotation ); double v[3]; v[0] = centerX; v[1] = centerY; v[2] = centerZ; m.inverseRotateVector( v ); m_centerX = v[0]; m_centerY = v[1]; viewWidth = height; viewHeight = width; } break; default: return; break; #endif // NEWVIEWPORT } if ( viewWidth > viewHeight ) { if ( m_viewDirection == ViewPerspective ) { m_zoomLevel = viewWidth / 2.0; } else { m_zoomLevel = viewWidth / 2.0; } } else { if ( m_viewDirection == ViewPerspective ) { m_zoomLevel = viewHeight / 2.0; } else { m_zoomLevel = viewHeight / 2.0; } } QString zoomStr; zoomStr.sprintf( "%f", m_zoomLevel ); emit zoomLevelChanged( zoomStr ); makeCurrent(); adjustViewport(); } void ModelViewport::checkGlErrors() { int error = glGetError(); if ( error ) { switch ( error ) { case GL_INVALID_VALUE: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Invalid Value").toUtf8() ); break; case GL_INVALID_ENUM: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Invalid Enum").toUtf8() ); break; case GL_INVALID_OPERATION: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Invalid Operation").toUtf8() ); break; case GL_STACK_OVERFLOW: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Stack Overflow").toUtf8() ); break; case GL_STACK_UNDERFLOW: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Stack Underflow").toUtf8() ); break; case GL_OUT_OF_MEMORY: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Out Of Memory").toUtf8() ); break; default: model_status( m_model, StatusNormal, STATUSTIME_NONE, tr("OpenGL error = Unknown").toUtf8() ); break; } } } void ModelViewport::copyContentsToTexture( Texture * tex ) { makeCurrent(); m_capture = true; if ( tex ) { unsigned w = this->width(); unsigned h = this->height(); // make sure texture can hold data if ( tex->m_data ) { unsigned bpp = (tex->m_format == Texture::FORMAT_RGB) ? 3 : 4; if ( (tex->m_width * tex->m_height * bpp) < (w * h * 4) ) { delete[] tex->m_data; tex->m_data = NULL; } } if ( tex->m_data == NULL ) { tex->m_data = new uint8_t[ w * h * 4 ]; } tex->m_width = w; tex->m_height = h; tex->m_format = Texture::FORMAT_RGBA; makeCurrent(); updateGL(); glReadPixels( 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, tex->m_data ); } makeCurrent(); glClearColor( m_backColor.red() / 256.0, m_backColor.green() / 256.0, m_backColor.blue() / 256.0, 1.0f ); m_capture = false; } void ModelViewport::updateCaptureGL() { m_capture = true; makeCurrent(); updateGL(); m_capture = false; } mm3d-master/src/depui/modelviewport.h000066400000000000000000000145051324021725400201620ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MVIEWPORT_H #define __MVIEWPORT_H #include #include #include #include #include #include #include "tool.h" #include "decal.h" #include "texture.h" #include #include using std::list; class Model; class Decal; class Toolbox; class QTimer; typedef list DecalList; class ModelViewport : public QGLWidget, public Tool::Parent { Q_OBJECT public: enum { MAX_VERTICAL_UNITS = 32767, MAX_HORIZONTAL_UNITS = 32767 }; enum _ViewOptions_e { ViewWireframe, ViewFlat, ViewSmooth, ViewTexture, ViewAlpha }; typedef enum _ViewOptions_e ViewOptionsE; enum _MouseOperation_e { MO_None, MO_Tool, MO_Pan, MO_PanButton, MO_Rotate, MO_RotateButton, }; typedef enum _MouseOperation_e MouseOperationE; enum _ScrollButton_e { ScrollButtonPan, ScrollButtonLeft, ScrollButtonRight, ScrollButtonUp, ScrollButtonDown, ScrollButtonMAX }; typedef enum _ScrollButton_e ScrollButtonE; struct _ViewState_t { ViewDirectionE direction; double rotation[3]; double translation[3]; double zoom; }; typedef struct _ViewState_t ViewStateT; ModelViewport( QWidget * parent = NULL ); virtual ~ModelViewport(); void freeTextures(); double getZoomLevel() { return m_zoomLevel; }; void frameArea( double x1, double y1, double z1, double x2, double y2, double z2 ); void zoomIn(); void zoomOut(); void scrollUp(); void scrollDown(); void scrollLeft(); void scrollRight(); void rotateUp(); void rotateDown(); void rotateLeft(); void rotateRight(); void rotateClockwise(); void rotateCounterClockwise(); void rotateViewport( double x, double y, double z = 0.0 ); void setModel( Model * model ) { m_model = model; }; void setToolbox( Toolbox * toolbox ) { m_toolbox = toolbox; }; int constructButtonState( QMouseEvent * e ); // Tool::Parent methods Model * getModel() { return m_model; }; ViewDirectionE getViewDirection() { return m_viewDirection; }; void updateView(); void update3dView(); void updateAllViews() { emit modelUpdated(); }; void getParentXYValue( int x, int y, double & xval, double & yval, bool selected ); void getRawParentXYValue( int x, int y, double & xval, double & yval ); const Matrix & getParentViewMatrix() const { return m_viewMatrix; }; const Matrix & getParentViewInverseMatrix() const { return m_invMatrix; }; bool getXValue( int x, int y, double * val ); bool getYValue( int x, int y, double * val ); bool getZValue( int x, int y, double * val ); void addDecal( Decal * decal ); void removeDecal( Decal * decal ); void copyContentsToTexture( Texture * tex ); void updateCaptureGL(); signals: void zoomLevelChanged( const QString & zoomStr ); void viewDirectionChanged( int dir ); void modelUpdated(); void viewportSaveState( int slotNumber, const ModelViewport::ViewStateT & viewState ); void viewportRecallState( int slotNumber ); public slots: void viewChangeEvent( int dir ); void setZoomLevel( double zoomLevel ); void setViewState( const ModelViewport::ViewStateT & viewState ); void scrollTimeout(); protected slots: void wheelEvent( QWheelEvent * e ); void mouseMoveEvent( QMouseEvent * e ); void mousePressEvent( QMouseEvent * e ); void mouseReleaseEvent( QMouseEvent * e ); void keyPressEvent( QKeyEvent * e ); void focusInEvent( QFocusEvent * e ); void focusOutEvent( QFocusEvent * e ); //void dragEnterEvent( QDragMoveEvent * e ); protected: void initializeGL(); void paintGL(); void resizeGL( int w, int h ); void checkGlErrors(); void updateBackground(); void adjustViewport(); void setViewportDraw(); void setViewportOverlay(); void drawGridLines(); void drawOrigin(); void drawBackground(); void drawOverlay(); void makeTextureFromImage( const QImage & i, GLuint & t ); double getUnitWidth(); Model * m_model; MouseOperationE m_operation; int m_activeButton; ViewDirectionE m_viewDirection; Matrix m_viewMatrix; Matrix m_invMatrix; double m_centerX; double m_centerY; double m_centerZ; double m_arcballPoint[3]; double m_rotX; double m_rotY; double m_rotZ; double m_width; double m_height; double m_zoomLevel; double m_unitWidth; double m_far; double m_near; double m_farOrtho; double m_nearOrtho; int m_viewportWidth; int m_viewportHeight; GLuint m_backgroundTexture; Texture * m_texture; std::string m_backgroundFile; QTimer * m_scrollTimer; bool m_inOverlay; ScrollButtonE m_overlayButton; GLuint m_scrollTextures[2]; bool m_capture; bool m_texturesLoaded; ViewOptionsE m_viewOptions; QPoint m_scrollStartPosition; QColor m_backColor; DecalList m_decals; Toolbox * m_toolbox; }; #endif // __MVIEWPORT_H mm3d-master/src/depui/textureframe.cc000066400000000000000000000076071324021725400201400ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "textureframe.h" #include "texwidget.h" #include "texture.h" #include "model.h" #include "log.h" #include #include #include TextureFrame::TextureFrame( QWidget * parent ) : QFrame( parent ), m_materialId( -1 ), m_texture( NULL ), m_3d( false ), m_overrideSize( false ), m_overWidth( 1 ), m_overHeight( 1 ) { setFrameStyle( StyledPanel ); setFrameShadow( Sunken ); m_textureWidget= new TextureWidget( this ); } TextureFrame::~TextureFrame() { } void TextureFrame::setModel( Model * model ) { m_model = model; if ( m_textureWidget ) { m_textureWidget->setModel( model ); } } void TextureFrame::set3d( bool o ) { m_3d = o; if ( m_textureWidget ) { m_textureWidget->set3d( o ); updateSize(); } } void TextureFrame::resizeEvent( QResizeEvent * e ) { updateSize(); } void TextureFrame::textureChangedEvent( int materialId ) { m_materialId = materialId - 1; m_texture = m_model->getTextureData( m_materialId ); // Okay to pass null here m_textureWidget->setTexture( m_materialId, m_texture ); updateSize(); } void TextureFrame::resizeTexture( int width, int height ) { if ( m_texture || m_overrideSize ) { if ( m_3d ) { m_textureWidget->move( PAD_SIZE, PAD_SIZE ); m_textureWidget->resize( width, height ); } else { float x = 0.0; float y = 0.0; float scaleX = 1.0; float scaleY = 1.0; if ( m_overrideSize ) { x = m_overWidth; y = m_overHeight; } else { if ( m_texture ) { x = m_texture->m_origWidth; y = m_texture->m_origHeight; } else { x = 256.0; y = 256.0; } } scaleX = width / x; scaleY = height / y; if ( scaleX < scaleY ) { m_textureWidget->move( PAD_SIZE, (int) ((this->height() - (y * scaleX)) / 2) + PAD_SIZE ); m_textureWidget->resize( (int) (x * scaleX), (int) (y * scaleX) ); } else { m_textureWidget->move( (int) ((this->width() - (x * scaleY)) / 2) + PAD_SIZE, PAD_SIZE ); m_textureWidget->resize( (int) (x * scaleY), (int) (y * scaleY) ); } } } else { m_textureWidget->move( PAD_SIZE, PAD_SIZE ); m_textureWidget->resize( this->width() - PAD_SIZE * 2, this->height() - PAD_SIZE * 2); } } void TextureFrame::setTexture( int materialId, Texture * tex ) { m_materialId = materialId; m_texture = tex; m_textureWidget->setTexture( m_materialId, tex ); updateSize(); } void TextureFrame::updateSize() { resizeTexture( width() - PAD_SIZE*2, height() - PAD_SIZE*2 ); } void TextureFrame::sizeOverride( int width, int height ) { m_textureWidget->resize( 0, 0 ); m_overrideSize = true; m_overWidth = width; m_overHeight = height; updateSize(); } mm3d-master/src/depui/textureframe.h000066400000000000000000000036221324021725400177730ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TEXFRAME_H #define __TEXFRAME_H #include #include class Model; class TextureWidget; class Texture; class TextureFrame : public QFrame { Q_OBJECT public: TextureFrame( QWidget * parent = NULL ); virtual ~TextureFrame(); void setModel( Model * model ); void set3d( bool o ); void resizeTexture( int width, int height ); void updateSize(); void sizeOverride( int width, int height ); TextureWidget * getTextureWidget() { return m_textureWidget; }; void setTexture( int materialId, Texture * tex ); enum { PAD_SIZE = 6 }; public slots: void resizeEvent( QResizeEvent * e ); void textureChangedEvent( int textureId ); protected: TextureWidget * m_textureWidget; int m_materialId; Texture * m_texture; bool m_3d; bool m_overrideSize; int m_overWidth; int m_overHeight; Model * m_model; }; #endif // __TEXFRAME_H mm3d-master/src/depui/texwidget.cc000066400000000000000000001656251324021725400174360ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "texwidget.h" #include "texture.h" #include "model.h" #include "log.h" #include "mm3dport.h" #include #include #include #include #include #include #include #include "pixmap/arrow.xpm" #include "pixmap/crosshairrow.xpm" #define VP_ZOOMSCALE 0.75 static int const SCROLL_SIZE = 16; struct _ScrollButton_t { int x; int y; int texIndex; float s1; float t1; float s2; float t2; float s3; float t3; float s4; float t4; }; typedef struct _ScrollButton_t ScrollButtonT; static ScrollButtonT s_buttons[ TextureWidget::ScrollButtonMAX ] = { { -18, -18, 1, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Pan { -52, -18, 0, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }, // Left { -35, -18, 0, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f }, // Right { -18, -35, 0, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }, // Up { -18, -52, 0, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f }, // Down }; using std::vector; using std::list; TextureWidget::TextureWidget( QWidget * parent ) : QGLWidget( parent ), m_sClamp( false ), m_tClamp( false ), m_zoom( 1.0 ), m_xCenter( 0.5 ), m_yCenter( 0.5 ), m_model( NULL ), m_materialId( -1 ), m_texture( NULL ), m_glTexture( 0 ), m_scrollTimer( new QTimer() ), m_overlayButton( ScrollButtonMAX ), m_drawMode( DM_Edit ), m_drawVertices( true ), m_drawBorder( false ), m_solidBackground( false ), m_operation( MouseSelect ), m_scaleKeepAspect( false ), m_scaleFromCenter( false ), m_selecting( false ), m_drawBounding( false ), m_drawRange( false ), m_interactive( false ), m_3d( false ), m_button( 0 ), m_animTimer( new QTimer() ), m_xMin( 0.0 ), m_xMax( 1.0 ), m_yMin( 0.0 ), m_yMax( 1.0 ), m_xRotPoint( 0.5 ), m_yRotPoint( 0.5 ), m_linesColor( 0xffffff ), m_selectionColor( 0xff0000 ) { connect( m_animTimer, SIGNAL(timeout()), this, SLOT(animationTimeout())); setFocusPolicy( Qt::WheelFocus ); connect( m_scrollTimer, SIGNAL(timeout()), this, SLOT(scrollTimeout())); setCursor( QCursor( Qt::ArrowCursor ) ); } TextureWidget::~TextureWidget() { m_animTimer->stop(); delete m_animTimer; m_animTimer = NULL; makeCurrent(); glDeleteTextures( 1, (GLuint *) &m_glTexture ); // Do NOT free m_texture. TextureManager does that. glDeleteTextures( 2, m_scrollTextures ); m_scrollTimer->stop(); delete m_scrollTimer; } void TextureWidget::initializeGL() { // general set-up glEnable( GL_TEXTURE_2D ); setAutoBufferSwap( false ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LEQUAL ); glClearColor( 0.80, 0.80, 0.80, 1.0 ); glClearDepth( 1.0f ); // set up overlay arrows QPixmap arrow( arrow_xpm ); QPixmap cross( crosshairrow_xpm ); QImage img; glGenTextures( 2, m_scrollTextures ); img = arrow.toImage(); makeTextureFromImage( img, m_scrollTextures[0] ); img = cross.toImage(); makeTextureFromImage( img, m_scrollTextures[1] ); // set up GL texture glGenTextures( 1, &m_glTexture ); // set up lighting GLfloat ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat position[] = { 0.0f, 0.0f, 3.0f, 0.0f }; glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE ); glLightfv( GL_LIGHT0, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_POSITION, position ); glEnable( GL_LIGHT0 ); glEnable( GL_LIGHTING ); } void TextureWidget::resizeGL( int w, int h ) { if ( h == 0 ) h = 1; m_viewportWidth = w; m_viewportHeight = h; updateViewport(); } void TextureWidget::updateViewport() { m_xMin = m_xCenter - (m_zoom / 2.0); m_xMax = m_xCenter + (m_zoom / 2.0); m_yMin = m_yCenter - (m_zoom / 2.0); m_yMax = m_yCenter + (m_zoom / 2.0); updateGL(); } void TextureWidget::paintGL() { makeCurrent(); paintInternal(); } void TextureWidget::paintOnGlWidget( QGLWidget * w ) { w->makeCurrent(); paintInternal(); } void TextureWidget::paintInternal() { setViewportDraw(); //log_debug( "paintInternal()\n" ); //log_debug( "(%f,%f) %f\n", m_xCenter, m_yCenter, m_zoom ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glLoadIdentity( ); glEnable( GL_LIGHTING ); if ( m_texture && !m_solidBackground ) { glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, m_glTexture ); } else { glDisable( GL_TEXTURE_2D ); } glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); if ( m_solidBackground ) { glColor3f( 0.0f, 0.0f, 0.0f ); float fval[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glMaterialfv( GL_FRONT, GL_AMBIENT, fval ); glMaterialfv( GL_FRONT, GL_DIFFUSE, fval ); glMaterialfv( GL_FRONT, GL_SPECULAR, fval ); glMaterialfv( GL_FRONT, GL_EMISSION, fval ); glMaterialf( GL_FRONT, GL_SHININESS, fval[0] ); } else if ( m_materialId >= 0 ) { glColor3f( 1.0f, 1.0f, 1.0f ); if ( m_model ) { float fval[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; m_model->getTextureAmbient( m_materialId, fval ); glMaterialfv( GL_FRONT, GL_AMBIENT, fval ); m_model->getTextureDiffuse( m_materialId, fval ); glMaterialfv( GL_FRONT, GL_DIFFUSE, fval ); m_model->getTextureSpecular( m_materialId, fval ); glMaterialfv( GL_FRONT, GL_SPECULAR, fval ); m_model->getTextureEmissive( m_materialId, fval ); glMaterialfv( GL_FRONT, GL_EMISSION, fval ); m_model->getTextureShininess( m_materialId, fval[0] ); glMaterialf( GL_FRONT, GL_SHININESS, fval[0] ); } else { float fval[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; glMaterialfv( GL_FRONT, GL_AMBIENT, fval ); fval[0] = fval[1] = fval[2] = 1.0f; glMaterialfv( GL_FRONT, GL_DIFFUSE, fval ); fval[0] = fval[1] = fval[2] = 0.0f; glMaterialfv( GL_FRONT, GL_SPECULAR, fval ); fval[0] = fval[1] = fval[2] = 0.0f; glMaterialfv( GL_FRONT, GL_EMISSION, fval ); glMaterialf( GL_FRONT, GL_SHININESS, 0.0f ); } } else { float fval[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; glMaterialfv( GL_FRONT, GL_AMBIENT, fval ); fval[0] = fval[1] = fval[2] = 1.0f; glMaterialfv( GL_FRONT, GL_DIFFUSE, fval ); fval[0] = fval[1] = fval[2] = 0.0f; glMaterialfv( GL_FRONT, GL_SPECULAR, fval ); fval[0] = fval[1] = fval[2] = 0.0f; glMaterialfv( GL_FRONT, GL_EMISSION, fval ); glMaterialf( GL_FRONT, GL_SHININESS, 0.0f ); if ( m_texture ) { glColor3f( 1.0f, 1.0f, 1.0f ); } else { glDisable( GL_LIGHTING ); glColor3f( 0.0f, 0.0f, 0.0f ); } } if ( m_materialId >= 0 && m_model && m_model->getMaterialType( m_materialId ) == Model::Material::MATTYPE_COLOR ) { GLubyte r = m_model->getMaterialColor( m_materialId, 0 ); GLubyte g = m_model->getMaterialColor( m_materialId, 1 ); GLubyte b = m_model->getMaterialColor( m_materialId, 2 ); glDisable( GL_TEXTURE_2D ); //glDisable( GL_LIGHTING ); glColor3ub( r, g, b ); } if ( m_materialId >= 0 && m_3d ) { glEnable( GL_DEPTH_TEST ); PORT_timeval tv; PORT_gettimeofday( &tv ); int ms = tv.tv_msec + (tv.tv_sec & 7) * 1000; float yRot = (float) ms / 4000.0 * 360.0; float xRot = (float) ms / 8000.0 * 360.0; glTranslatef( 0.0, 0.0, -5.0 ); glRotatef( yRot, 0.0, 1.0, 0.0 ); glRotatef( xRot, 1.0, 0.0, 0.0 ); glBegin( GL_QUADS ); // Front glTexCoord2f( 0.0, 0.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( 1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( -1.0, 1.0, 1.0 ); // Back glTexCoord2f( 0.0, 0.0 ); glNormal3f( 0.0, 0.0, -1.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( 0.0, 0.0, -1.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( 0.0, 0.0, -1.0 ); glVertex3f( -1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( 0.0, 0.0, -1.0 ); glVertex3f( 1.0, 1.0, -1.0 ); // Left glTexCoord2f( 0.0, 0.0 ); glNormal3f( 1.0, 0.0, 0.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( 1.0, 0.0, 0.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( 1.0, 0.0, 0.0 ); glVertex3f( 1.0, 1.0, -1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( 1.0, 0.0, 0.0 ); glVertex3f( 1.0, 1.0, 1.0 ); // Right glTexCoord2f( 0.0, 0.0 ); glNormal3f( -1.0, 0.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( -1.0, 0.0, 0.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( -1.0, 0.0, 0.0 ); glVertex3f( -1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( -1.0, 0.0, 0.0 ); glVertex3f( -1.0, 1.0, -1.0 ); // Top glTexCoord2f( 0.0, 0.0 ); glNormal3f( 0.0, 1.0, 0.0 ); glVertex3f( -1.0, 1.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( 0.0, 1.0, 0.0 ); glVertex3f( 1.0, 1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( 0.0, 1.0, 0.0 ); glVertex3f( 1.0, 1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( 0.0, 1.0, 0.0 ); glVertex3f( -1.0, 1.0, 1.0 ); // Bottom glTexCoord2f( 0.0, 0.0 ); glNormal3f( 0.0, -1.0, 0.0 ); glVertex3f( 1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 0.0 ); glNormal3f( 0.0, -1.0, 0.0 ); glVertex3f( -1.0, -1.0, -1.0 ); glTexCoord2f( 1.0, 1.0 ); glNormal3f( 0.0, -1.0, 0.0 ); glVertex3f( -1.0, -1.0, 1.0 ); glTexCoord2f( 0.0, 1.0 ); glNormal3f( 0.0, -1.0, 0.0 ); glVertex3f( 1.0, -1.0, 1.0 ); glEnd(); glDisable( GL_DEPTH_TEST ); } else { glBegin( GL_QUADS ); glTexCoord2f( m_xMin, m_yMin ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( m_xMin, m_yMin, 0.0 ); glTexCoord2f( m_xMax, m_yMin ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( m_xMax, m_yMin, 0.0 ); glTexCoord2f( m_xMax, m_yMax ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( m_xMax, m_yMax, 0.0 ); glTexCoord2f( m_xMin, m_yMax ); glNormal3f( 0.0, 0.0, 1.0 ); glVertex3f( m_xMin, m_yMax, 0.0 ); glEnd(); } //glLoadIdentity( ); glDisable( GL_TEXTURE_2D ); glDisable( GL_LIGHTING ); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); if ( m_drawBorder ) { glColor3f( 0.7, 0.7, 0.7 ); glBegin( GL_QUADS ); glVertex3f( 0.0f, 0.0f, -0.25f ); glVertex3f( 1.0f, 0.0f, -0.25f ); glVertex3f( 1.0f, 1.0f, -0.25f ); glVertex3f( 0.0f, 1.0f, -0.25f ); glEnd(); } useLinesColor(); if ( m_operation == MouseRange ) { glColor3f( 0.7, 0.7, 0.7 ); } switch ( m_drawMode ) { case DM_Edit: glBegin( GL_TRIANGLES ); drawTriangles(); glEnd(); break; case DM_Edges: glBegin( GL_TRIANGLES ); drawTriangles(); glEnd(); break; case DM_Filled: glColor3f( 0.0, 0.0, 0.8 ); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glBegin( GL_TRIANGLES ); drawTriangles(); glEnd(); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); break; case DM_FilledEdges: glColor3f( 0.0, 0.0, 0.8 ); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glBegin( GL_TRIANGLES ); drawTriangles(); glEnd(); glClear( GL_DEPTH_BUFFER_BIT ); glColor3f( 1.0, 1.0, 1.0 ); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); glBegin( GL_TRIANGLES ); drawTriangles(); glEnd(); break; default: log_error( "Unknown draw mode: %d\n", m_drawMode ); break; } // TODO may want to make "draw points" a separate property if ( m_operation == MouseRange ) { useLinesColor(); } // TODO may want to make "draw points" a separate property if ( m_operation != MouseRange || m_drawVertices ) { glPointSize( 3.0 ); glBegin( GL_POINTS ); for ( unsigned t = 0; t < m_triangles.size(); t++ ) { for ( unsigned v = 0; v < 3; v++ ) { TextureVertexT * vert = m_vertices[ m_triangles[t]->vertex[v] ]; if ( m_drawMode == DM_Edit && vert->selected ) { useSelectionColor(); } else { useLinesColor(); } //glVertex3f( (vert->s - m_xMin) / m_zoom, (vert->t - m_yMin) / m_zoom, -0.5 ); glVertex3f( vert->s, vert->t, -0.5 ); } } glEnd(); } if ( m_drawBounding ) { drawSelectBox(); } if ( m_drawRange ) { drawRangeBox(); } if ( m_operation == MouseRotate ) { drawRotationPoint(); } if ( m_interactive ) { drawOverlay(); } swapBuffers(); } void TextureWidget::drawTriangles() { bool wrapLeft = false; bool wrapRight = false; bool wrapTop = false; bool wrapBottom = false; for ( unsigned t = 0; t < m_triangles.size(); t++ ) { TextureTriangleT * triangle = m_triangles[t]; wrapLeft = false; wrapRight = false; wrapTop = false; wrapBottom = false; for ( unsigned v = 0; v < 3; v++ ) { glVertex3f( m_vertices[ triangle->vertex[v] ]->s, m_vertices[ triangle->vertex[v] ]->t, -0.5 ); if ( m_drawMode != DM_Edit ) { if ( m_vertices[ triangle->vertex[v] ]->s < 0.0 ) { wrapLeft = true; } if ( m_vertices[ triangle->vertex[v] ]->s > 1.0 ) { wrapRight = true; } if ( m_vertices[ triangle->vertex[v] ]->t < 0.0 ) { wrapBottom = true; } if ( m_vertices[ triangle->vertex[v] ]->t > 1.0 ) { wrapTop = true; } } } if ( m_drawMode != DM_Edit ) { if ( wrapLeft ) { for ( unsigned v = 0; v < 3; v++ ) { glVertex3f( m_vertices[ triangle->vertex[v] ]->s + 1.0, m_vertices[ triangle->vertex[v] ]->t, -0.5 ); } } if ( wrapRight ) { for ( unsigned v = 0; v < 3; v++ ) { glVertex3f( m_vertices[ triangle->vertex[v] ]->s - 1.0, m_vertices[ triangle->vertex[v] ]->t, -0.5 ); } } if ( wrapBottom ) { for ( unsigned v = 0; v < 3; v++ ) { glVertex3f( m_vertices[ triangle->vertex[v] ]->s, m_vertices[ triangle->vertex[v] ]->t + 1.0, -0.5 ); } } if ( wrapTop ) { for ( unsigned v = 0; v < 3; v++ ) { glVertex3f( m_vertices[ triangle->vertex[v] ]->s, m_vertices[ triangle->vertex[v] ]->t - 1.0, -0.5 ); } } } } } void TextureWidget::animationTimeout() { updateGL(); } void TextureWidget::setModel( Model * model ) { m_model = model; m_texture = NULL; clearCoordinates(); glDisable( GL_TEXTURE_2D ); } void TextureWidget::set3d( bool o ) { m_3d = o; updateViewport(); if ( o ) { m_animTimer->start( 30 ); } else { m_animTimer->stop(); } } void TextureWidget::setInteractive( bool o ) { m_interactive = o; updateGL(); } void TextureWidget::setTexture( int materialId, Texture * texture ) { m_materialId = materialId; m_texture = texture; m_sClamp = true; m_tClamp = true; if ( m_model ) { m_sClamp = m_model->getTextureSClamp( materialId ); m_tClamp = m_model->getTextureTClamp( materialId ); } if ( m_texture ) { m_zoom = 1.0; m_xCenter = 0.5; m_yCenter = 0.5; updateViewport(); /* m_xMin = m_xCenter - w; m_xMax = m_xCenter + w; m_yMin = m_yCenter - w; m_yMax = m_yCenter + w; */ glBindTexture( GL_TEXTURE_2D, m_glTexture ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (m_sClamp ? GL_CLAMP : GL_REPEAT) ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (m_tClamp ? GL_CLAMP : GL_REPEAT) ); GLuint format = m_texture->m_format == Texture::FORMAT_RGBA ? GL_RGBA : GL_RGB; gluBuild2DMipmaps( GL_TEXTURE_2D, format, m_texture->m_width, m_texture->m_height, format, GL_UNSIGNED_BYTE, m_texture->m_data ); } else { m_zoom = 1.0; m_xCenter = 0.5; m_yCenter = 0.5; updateViewport(); } resizeGL( this->width(), this->height() ); updateGL(); } void TextureWidget::vFlipCoordinates() { for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->selected ) { m_vertices[v]->t = 1.0 - m_vertices[v]->t; } } updateGL(); } void TextureWidget::hFlipCoordinates() { for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->selected ) { m_vertices[v]->s = 1.0 - m_vertices[v]->s; } } updateGL(); } void TextureWidget::rotateCoordinatesCcw() { for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->selected ) { double temp = m_vertices[v]->t; m_vertices[v]->t = m_vertices[v]->s; m_vertices[v]->s = 1.0 - temp; } } updateGL(); } void TextureWidget::rotateCoordinatesCw() { for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->selected ) { double temp = m_vertices[v]->t; m_vertices[v]->t = 1.0 - m_vertices[v]->s; m_vertices[v]->s = temp; } } updateGL(); } int TextureWidget::addVertex( double s, double t ) { int index = m_vertices.size(); TextureVertexT * vert = new TextureVertexT; vert->s = s; vert->t = t; vert->selected = true; m_vertices.push_back( vert ); return index; } int TextureWidget::addTriangle( int v1, int v2, int v3 ) { int vCount = m_vertices.size(); if ( v1 >= 0 && v1 < vCount && v2 >= 0 && v2 < vCount && v3 >= 0 && v3 < vCount ) { int index = m_triangles.size(); TextureTriangleT * triangle = new TextureTriangleT; triangle->vertex[0] = v1; triangle->vertex[1] = v2; triangle->vertex[2] = v3; m_triangles.push_back( triangle ); return index; } return -1; } void TextureWidget::mousePressEvent( QMouseEvent * e ) { if ( m_interactive ) { int w = this->width(); int h = this->height(); m_lastXPos = e->pos().x(); m_lastYPos = e->pos().y(); m_button = m_button | e->button(); int bx = e->pos().x(); int by = h - e->pos().y(); m_overlayButton = ScrollButtonMAX; int sx = 0; int sy = 0; int size = SCROLL_SIZE; for ( int b = 0; m_overlayButton == ScrollButtonMAX && b < ScrollButtonMAX; b++ ) { sx = s_buttons[b].x; sy = s_buttons[b].y; if ( (bx >= w + sx) && (bx <= w + sx + size) && (by >= h + sy) && (by <= h + sy + size) ) { m_overlayButton = (ScrollButtonE) b; switch ( m_overlayButton ) { case ScrollButtonPan: break; case ScrollButtonUp: scrollUp(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonDown: scrollDown(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonLeft: scrollLeft(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; case ScrollButtonRight: scrollRight(); m_scrollTimer->setSingleShot( true ); m_scrollTimer->start( 300 ); break; default: break; } } } if ( m_overlayButton == ScrollButtonMAX ) { if ( e->button() & Qt::MidButton ) { // We're panning } else { switch ( m_operation ) { case MouseSelect: if ( !( (e->modifiers() & Qt::ShiftModifier) || (e->button() & Qt::RightButton) ) ) { clearSelected(); } m_xSel1 = (m_lastXPos / (double) this->width()) * (m_xMax - m_xMin) + m_xMin; m_ySel1 = (1.0 - (m_lastYPos / (double) this->height())) * (m_yMax - m_yMin) + m_yMin; m_selecting = ( e->button() & Qt::RightButton ) ? false : true; m_drawBounding = true; break; case MouseMove: break; case MouseScale: startScale( (m_lastXPos / (double) this->width()) * (m_xMax - m_xMin) + m_xMin , (1.0 - (m_lastYPos / (double) this->height())) * (m_yMax - m_yMin) + m_yMin ); break; case MouseRotate: { double aspect = (double) this->width() / (double) this->height(); if ( (e->button() & Qt::RightButton) ) { m_xRotPoint = (m_lastXPos / (double) this->width()) * (m_xMax - m_xMin) + m_xMin; m_yRotPoint = (1.0 - (m_lastYPos / (double) this->height())) * (m_yMax - m_yMin) + m_yMin; } else { m_xRotStart = (m_lastXPos / (double) this->width()) * (m_xMax - m_xMin) + m_xMin; m_yRotStart = (1.0 - (m_lastYPos / (double) this->height())) * (m_yMax - m_yMin) + m_yMin; m_xRotStart -= m_xRotPoint; m_yRotStart -= m_yRotPoint; double opposite = m_yRotStart; double adjacent = m_xRotStart * aspect; if ( adjacent < 0.0001 && adjacent > -0.0001 ) { adjacent = (adjacent >= 0 ) ? 0.0001 : -0.0001; } double angle = atan( opposite / adjacent ); float quad = PIOVER180 * 90; if ( adjacent < 0 ) { if ( opposite < 0 ) { angle = -(quad) - ( (quad) - angle ); } else { angle = (quad) + ( (quad) + angle ); } } m_startAngle = angle; } freeRotateVertices(); for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->selected ) { RotateVertexT * rot = new RotateVertexT; rot->x = (m_vertices[v]->s - m_xRotPoint) * aspect; rot->y = m_vertices[v]->t - m_yRotPoint; rot->v = v; m_rotateVertices.push_back( rot ); } } updateGL(); } break; case MouseRange: { m_dragAll = false; m_dragTop = false; m_dragBottom = false; m_dragLeft = false; m_dragRight = false; double windowX = getWindowXCoord( m_lastXPos ); double windowY = getWindowYCoord( m_lastYPos ); getDragDirections( windowX, windowY, m_dragAll, m_dragTop, m_dragBottom, m_dragLeft, m_dragRight ); setDragCursor( m_dragAll, m_dragTop, m_dragBottom, m_dragLeft, m_dragRight ); } break; default: log_error( "Unknown mouse operation: %d\n", m_operation ); break; } } } } } void TextureWidget::mouseReleaseEvent( QMouseEvent * e ) { if ( m_interactive ) { if ( m_overlayButton == ScrollButtonMAX ) { int x = e->pos().x(); int y = e->pos().y(); if ( e->button() & Qt::MidButton ) { // We're panning } else { switch ( m_operation ) { case MouseSelect: m_drawBounding = false; updateSelectRegion( (x / (double) this->width()) * (m_xMax - m_xMin) + m_xMin, (1.0 - (y / (double) this->height())) * (m_yMax - m_yMin) + m_yMin ); selectDone(); emit updateSelectionDoneSignal(); break; case MouseMove: moveSelectedVertices( ((x - m_lastXPos) / (double) this->width()) * (m_xMax - m_xMin), (-(y - m_lastYPos) / (double) this->height()) * (m_yMax - m_yMin) ); emit updateCoordinatesSignal(); emit updateCoordinatesDoneSignal(); break; case MouseRotate: // Nothing to do here emit updateCoordinatesDoneSignal(); break; case MouseScale: // Nothing to do here emit updateCoordinatesDoneSignal(); break; case MouseRange: if ( m_button & Qt::LeftButton ) { if ( m_dragAll || m_dragTop || m_dragBottom || m_dragLeft || m_dragRight ) { emit updateRangeDoneSignal(); } } else { if ( m_dragAll ) { emit updateSeamDoneSignal(); } } break; default: log_error( "Unknown mouse operation: %d\n", m_operation ); break; } } } else { m_overlayButton = ScrollButtonMAX; m_scrollTimer->stop(); } m_button = m_button & ~(e->button()); } } void TextureWidget::mouseMoveEvent( QMouseEvent * e ) { if ( m_interactive ) { int x = e->pos().x(); int y = e->pos().y(); if ( m_overlayButton == ScrollButtonMAX ) { if ( m_button != 0 ) { if ( m_button & Qt::MidButton ) { double xDiff = (double) -(x - m_lastXPos); double yDiff = (double) (y - m_lastYPos); xDiff = xDiff / (double) m_viewportWidth; yDiff = yDiff / (double) m_viewportHeight; xDiff *= m_zoom; yDiff *= m_zoom; m_xCenter += xDiff; m_yCenter += yDiff; m_xMin += xDiff; m_yMin += yDiff; m_xMax += xDiff; m_yMax += yDiff; updateViewport(); } else { switch ( m_operation ) { case MouseSelect: /* updateSelectRegion( x / (double) this->width(), 1.0 - (y / (double) this->height()) ); */ updateSelectRegion( (x / (double) this->width()) * m_zoom + m_xMin, (1.0 - (y / (double) this->height())) * m_zoom + m_yMin ); break; case MouseMove: moveSelectedVertices( ((x - m_lastXPos) / (double) this->width()) * m_zoom, (-(y - m_lastYPos) / (double) this->height()) * m_zoom); emit updateCoordinatesSignal(); break; case MouseRotate: { double xNew = (x / (double) this->width()) * (m_xMax - m_xMin) + m_xMin; double yNew = (1.0 - (y / (double) this->height())) * (m_yMax - m_yMin) + m_yMin; xNew -= m_xRotPoint; yNew -= m_yRotPoint; double aspect = (double) this->width() / (double) this->height(); double opposite = yNew; double adjacent = xNew * aspect; if ( adjacent < 0.0001 && adjacent > -0.0001 ) { adjacent = (adjacent >= 0 ) ? 0.0001 : -0.0001; } double angle = atan( opposite / adjacent ); float quad = PIOVER180 * 90; if ( adjacent < 0 ) { if ( opposite < 0 ) { angle = -(quad) - ( (quad) - angle ); } else { angle = (quad) + ( (quad) + angle ); } } rotateSelectedVertices( angle - m_startAngle ); emit updateCoordinatesSignal(); } break; case MouseScale: scaleSelectedVertices( (x / (double) this->width()) * m_zoom + m_xMin, (1.0 - (y / (double) this->height())) * m_zoom + m_yMin ); emit updateCoordinatesSignal(); break; case MouseRange: if ( m_button & Qt::LeftButton ) { double xThen = getWindowXCoord( m_lastXPos ); double xNow = getWindowXCoord( x ); double yThen = getWindowYCoord( m_lastYPos ); double yNow = getWindowYCoord( y ); double xDiff = xNow - xThen; double yDiff = yNow - yThen; if ( m_dragLeft || m_dragAll ) { m_xRangeMin += xDiff; if ( m_xRangeMin > m_xRangeMax ) { m_xRangeMax = m_xRangeMin; } } if ( m_dragRight || m_dragAll ) { m_xRangeMax += xDiff; if ( m_xRangeMax < m_xRangeMin ) { m_xRangeMin = m_xRangeMax; } } if ( m_dragBottom || m_dragAll ) { m_yRangeMin += yDiff; if ( m_yRangeMin > m_yRangeMax ) { m_yRangeMax = m_yRangeMin; } } if ( m_dragTop || m_dragAll ) { m_yRangeMax += yDiff; if ( m_yRangeMax < m_yRangeMin ) { m_yRangeMin = m_yRangeMax; } } if ( m_dragAll || m_dragTop || m_dragBottom || m_dragLeft || m_dragRight ) { emit updateRangeSignal(); } } else { if ( m_dragAll ) { double xThen = getWindowXCoord( m_lastXPos ); double xNow = getWindowXCoord( x ); double yThen = getWindowYCoord( m_lastYPos ); double yNow = getWindowYCoord( y ); double xDiff = xNow - xThen; double yDiff = yNow - yThen; xDiff *= -(2 * PI); yDiff *= -(2 * PI); emit updateSeamSignal( xDiff, yDiff ); } } break; default: log_error( "Unknown mouse operation: %d\n", m_operation ); break; } } } else { updateCursorShape( x, y ); } } else { if ( m_overlayButton == ScrollButtonPan ) { double xDiff = (double) -(x - m_lastXPos); double yDiff = (double) (y - m_lastYPos); xDiff = xDiff / (double) m_viewportWidth; yDiff = yDiff / (double) m_viewportHeight; xDiff *= m_zoom; yDiff *= m_zoom; m_xCenter += xDiff; m_yCenter += yDiff; m_xMin += xDiff; m_yMin += yDiff; m_xMax += xDiff; m_yMax += yDiff; updateViewport(); } } m_lastXPos = x; m_lastYPos = y; } } void TextureWidget::wheelEvent( QWheelEvent * e ) { if ( m_interactive ) { if ( e->delta() > 0 ) { zoomIn(); } else { zoomOut(); } } } void TextureWidget::keyPressEvent( QKeyEvent * e ) { if ( m_interactive ) { switch ( e->key() ) { case Qt::Key_Home: { if ( (e->modifiers() & Qt::ShiftModifier) == Qt::ShiftModifier ) { if ( m_drawMode == DM_Edit ) { if ( m_operation == MouseRange ) { m_xCenter = (m_xRangeMax - m_xRangeMin) / 2.0 + m_xRangeMin; m_yCenter = (m_yRangeMax - m_yRangeMin) / 2.0 + m_yRangeMin; double xzoom = m_xRangeMax - m_xRangeMin; double yzoom = m_yRangeMax - m_yRangeMin; m_zoom = (xzoom > yzoom) ? xzoom : yzoom; m_zoom *= 1.10; updateViewport(); } else { bool first = true; double xMin = 0.0; double xMax = 0.0; double yMin = 0.0; double yMax = 0.0; size_t vcount = m_vertices.size(); for ( size_t v = 1; v < vcount; v++ ) { if ( m_vertices[v]->selected ) { if ( first ) { xMin = m_vertices[v]->s; yMin = m_vertices[v]->t; first = false; } else { if ( m_vertices[v]->s < xMin ) xMin = m_vertices[v]->s; if ( m_vertices[v]->s > xMax ) xMax = m_vertices[v]->s; if ( m_vertices[v]->t < yMin ) yMin = m_vertices[v]->t; if ( m_vertices[v]->t > yMax ) yMax = m_vertices[v]->t; } } } if ( !first ) { m_xCenter = (xMax - xMin) / 2.0 + xMin; m_yCenter = (yMax - yMin) / 2.0 + yMin; double xzoom = xMax - xMin; double yzoom = yMax - yMin; m_zoom = (xzoom > yzoom) ? xzoom : yzoom; m_zoom *= 1.10; updateViewport(); } } } } else { m_xCenter = 0.5; m_yCenter = 0.5; m_zoom = 1.0; updateViewport(); } } break; case Qt::Key_Equal: case Qt::Key_Plus: { zoomIn(); } break; case Qt::Key_Minus: case Qt::Key_Underscore: { zoomOut(); } break; case Qt::Key_0: m_xCenter = 0.5; m_yCenter = 0.5; updateViewport(); break; case Qt::Key_Up: scrollUp(); break; case Qt::Key_Down: scrollDown(); break; case Qt::Key_Left: scrollLeft(); break; case Qt::Key_Right: scrollRight(); break; default: QGLWidget::keyPressEvent( e ); break; } } else { QGLWidget::keyPressEvent( e ); } } void TextureWidget::zoomIn() { if ( m_interactive ) { if ( (m_zoom / VP_ZOOMSCALE) > 0.0001 ) { m_zoom *= (VP_ZOOMSCALE); } QString zoomStr; zoomStr.sprintf( "%f", (float) m_zoom ); emit zoomLevelChanged( zoomStr ); updateViewport(); } } void TextureWidget::zoomOut() { if ( m_interactive ) { if ( (m_zoom / VP_ZOOMSCALE) < 250000 ) { m_zoom /= VP_ZOOMSCALE; } QString zoomStr; zoomStr.sprintf( "%f", (float) m_zoom ); emit zoomLevelChanged( zoomStr ); updateViewport(); } } void TextureWidget::setZoomLevel( double zoom ) { if ( m_interactive ) { m_zoom = zoom; updateViewport(); } } void TextureWidget::scrollTimeout() { switch ( m_overlayButton ) { case ScrollButtonUp: scrollUp(); break; case ScrollButtonDown: scrollDown(); break; case ScrollButtonLeft: scrollLeft(); break; case ScrollButtonRight: scrollRight(); break; default: m_scrollTimer->stop(); return; } m_scrollTimer->setSingleShot( false ); m_scrollTimer->start( 100 ); } void TextureWidget::scrollUp() { m_yCenter += m_zoom * 0.10; updateViewport(); } void TextureWidget::scrollDown() { m_yCenter -= m_zoom * 0.10; updateViewport(); } void TextureWidget::scrollLeft() { m_xCenter -= m_zoom * 0.10; updateViewport(); } void TextureWidget::scrollRight() { m_xCenter += m_zoom * 0.10; updateViewport(); } void TextureWidget::moveSelectedVertices( double x, double y ) { for ( unsigned t = 0; t < m_vertices.size(); t++ ) { if ( m_vertices[t]->selected ) { m_vertices[t]->s += x; m_vertices[t]->t += y; } } updateGL(); } void TextureWidget::updateSelectRegion( double x, double y ) { m_xSel2 = x; m_ySel2 = y; updateGL(); } void TextureWidget::setViewportDraw() { glViewport( 0, 0, ( GLint ) m_viewportWidth, ( GLint ) m_viewportHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); GLfloat ratio = ( GLfloat ) m_viewportWidth / ( GLfloat ) m_viewportHeight; glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); if ( m_3d ) { gluPerspective( 45.0f, ratio, 0.01, 30.0 ); } else { glOrtho( m_xMin, m_xMax, m_yMin, m_yMax, -1.0, 1.0 ); } glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } void TextureWidget::setViewportOverlay() { glViewport( 0, 0, ( GLint ) m_viewportWidth, ( GLint ) m_viewportHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glOrtho( 0, this->width(), 0, this->height(), -1.0, 1.0 ); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } void TextureWidget::drawOverlay() { setViewportOverlay(); glDisable( GL_LIGHTING ); glColor3f( 1.0f, 1.0f, 1.0f ); glEnable( GL_TEXTURE_2D ); int w = this->width(); int h = this->height(); int sx = 0; int sy = 0; int size = SCROLL_SIZE; for ( int b = 0; b < ScrollButtonMAX; b++ ) { ScrollButtonT * sbt = &s_buttons[b]; sx = sbt->x; sy = sbt->y; glBindTexture( GL_TEXTURE_2D, m_scrollTextures[ sbt->texIndex ] ); glBegin( GL_QUADS ); glTexCoord2f( sbt->s1, sbt->t1 ); glVertex3f( w + sx, h + sy, 0 ); glTexCoord2f( sbt->s2, sbt->t2 ); glVertex3f( w + sx + size, h + sy, 0 ); glTexCoord2f( sbt->s3, sbt->t3 ); glVertex3f( w + sx + size, h + sy + size, 0 ); glTexCoord2f( sbt->s4, sbt->t4 ); glVertex3f( w + sx, h + sy + size, 0 ); glEnd(); } glDisable( GL_TEXTURE_2D ); } void TextureWidget::makeTextureFromImage( const QImage & i, GLuint & t ) { glBindTexture( GL_TEXTURE_2D, t ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); int w = i.width(); int h = i.height(); unsigned pixelCount = w * i.height(); uint8_t * data = new uint8_t[ pixelCount * 3 ]; for ( int y = 0; y < h; y ++ ) { for ( int x = 0; x < w; x++ ) { QRgb p = i.pixel( x, h - y - 1 ); data[ ((y * w + x)*3) + 0 ] = qRed( p ); data[ ((y * w + x)*3) + 1 ] = qGreen( p ); data[ ((y * w + x)*3) + 2 ] = qBlue( p ); } } gluBuild2DMipmaps( GL_TEXTURE_2D, GL_RGB, w, h, GL_RGB, GL_UNSIGNED_BYTE, data ); delete[] data; } void TextureWidget::selectDone() { if ( m_xSel1 > m_xSel2 ) { double temp = m_xSel2; m_xSel2 = m_xSel1; m_xSel1 = temp; } if ( m_ySel1 > m_ySel2 ) { double temp = m_ySel2; m_ySel2 = m_ySel1; m_ySel1 = temp; } for ( unsigned v = 0; v < m_vertices.size(); v++ ) { if ( m_vertices[v]->s >= m_xSel1 && m_vertices[v]->s <= m_xSel2 && m_vertices[v]->t >= m_ySel1 && m_vertices[v]->t <= m_ySel2 ) { m_vertices[v]->selected = m_selecting; } } updateGL(); } void TextureWidget::setTextureCount( unsigned c ) { setTexture( m_materialId, m_texture ); } void TextureWidget::setMouseOperation( MouseOperationE op ) { m_operation = op; m_drawRange = false; if ( op == MouseRange ) { m_drawRange = true; } } void TextureWidget::setDrawMode( DrawModeE dm ) { m_drawMode = dm; } void TextureWidget::drawSelectBox() { glEnable( GL_COLOR_LOGIC_OP ); glColor3f( 1.0, 1.0, 1.0 ); glLogicOp( GL_XOR ); glBegin( GL_LINES ); glVertex3f( m_xSel1, m_ySel1, -0.75 ); glVertex3f( m_xSel1, m_ySel2, -0.75 ); glVertex3f( m_xSel1, m_ySel2, -0.75 ); glVertex3f( m_xSel2, m_ySel2, -0.75 ); glVertex3f( m_xSel2, m_ySel2, -0.75 ); glVertex3f( m_xSel2, m_ySel1, -0.75 ); glVertex3f( m_xSel2, m_ySel1, -0.75 ); glVertex3f( m_xSel1, m_ySel1, -0.75 ); glEnd(); glLogicOp( GL_COPY ); glDisable( GL_LOGIC_OP ); } void TextureWidget::drawRangeBox() { glLogicOp( GL_COPY ); glDisable( GL_LOGIC_OP ); glColor3f( 1.0, 1.0, 1.0 ); glBegin( GL_LINES ); glVertex3f( m_xRangeMin, m_yRangeMin, -0.95 ); glVertex3f( m_xRangeMin, m_yRangeMax, -0.95 ); glVertex3f( m_xRangeMin, m_yRangeMax, -0.95 ); glVertex3f( m_xRangeMax, m_yRangeMax, -0.95 ); glVertex3f( m_xRangeMax, m_yRangeMax, -0.95 ); glVertex3f( m_xRangeMax, m_yRangeMin, -0.95 ); glVertex3f( m_xRangeMax, m_yRangeMin, -0.95 ); glVertex3f( m_xRangeMin, m_yRangeMin, -0.95 ); glEnd(); } void TextureWidget::drawRotationPoint() { glLogicOp( GL_COPY ); glDisable( GL_LOGIC_OP ); glColor3f( 0.0, 1.0, 0.0 ); glBegin( GL_LINES ); double offset = m_zoom * 0.04; double aspect = (double) this->width() / (double) this->height(); double xoff = offset / aspect; double yoff = offset; glVertex3f( m_xRotPoint - xoff, m_yRotPoint + 0.0, -0.95 ); glVertex3f( m_xRotPoint + 0.0, m_yRotPoint - yoff, -0.95 ); glVertex3f( m_xRotPoint + 0.0, m_yRotPoint - yoff, -0.95 ); glVertex3f( m_xRotPoint + xoff, m_yRotPoint + 0.0, -0.95 ); glVertex3f( m_xRotPoint + xoff, m_yRotPoint + 0.0, -0.95 ); glVertex3f( m_xRotPoint + 0.0, m_yRotPoint + yoff, -0.95 ); glVertex3f( m_xRotPoint + 0.0, m_yRotPoint + yoff, -0.95 ); glVertex3f( m_xRotPoint - xoff, m_yRotPoint + 0.0, -0.95 ); glEnd(); } void TextureWidget::clearSelected() { for ( unsigned v = 0; v < m_vertices.size(); v++ ) { m_vertices[v]->selected = false; } } double TextureWidget::getWindowXCoord( int x ) { return (x / (double) m_viewportWidth) * m_zoom + m_xMin; } double TextureWidget::getWindowYCoord( int y ) { return ((m_viewportHeight - y) / (double) m_viewportHeight) * m_zoom + m_yMin; } void TextureWidget::updateCursorShape( int x, int y ) { if ( m_interactive ) { int w = this->width(); int h = this->height(); int sx = 0; int sy = 0; int size = SCROLL_SIZE; int bx = x; int by = h - y; ScrollButtonE button = ScrollButtonMAX; for ( int b = 0; button == ScrollButtonMAX && b < ScrollButtonMAX; b++ ) { sx = s_buttons[b].x; sy = s_buttons[b].y; if ( (bx >= w + sx) && (bx <= w + sx + size) && (by >= h + sy) && (by <= h + sy + size) ) { button = (ScrollButtonE) b; } } switch ( button ) { case ScrollButtonPan: case ScrollButtonUp: case ScrollButtonDown: case ScrollButtonLeft: case ScrollButtonRight: break; default: break; } if ( button == ScrollButtonMAX ) { if ( m_operation == MouseRange ) { bool dragAll = false; bool dragTop = false; bool dragBottom = false; bool dragLeft = false; bool dragRight = false; double windowX = getWindowXCoord( x ); double windowY = getWindowYCoord( y ); getDragDirections( windowX, windowY, dragAll, dragTop, dragBottom, dragLeft, dragRight ); setDragCursor( dragAll, dragTop, dragBottom, dragLeft, dragRight ); return; } } } setDragCursor( false, false, false, false, false ); } void TextureWidget::getDragDirections( double windowX, double windowY, bool & dragAll, bool & dragTop, bool & dragBottom, bool & dragLeft, bool & dragRight ) { dragAll = false; dragTop = false; dragBottom = false; dragLeft = false; dragRight = false; double prox = (6.0 / m_viewportWidth) * m_zoom; if ( (windowX >= (m_xRangeMin - prox)) && (windowX <= (m_xRangeMax + prox)) && (windowY >= (m_yRangeMin - prox)) && (windowY <= (m_yRangeMax + prox)) ) { if ( fabs(m_xRangeMin - windowX) <= prox ) { dragLeft = true; } if ( fabs(m_xRangeMax - windowX) <= prox ) { dragRight = true; } if ( fabs(m_yRangeMin - windowY) <= prox ) { dragBottom = true; } if ( fabs(m_yRangeMax - windowY) <= prox ) { dragTop = true; } if ( dragLeft && dragRight ) { // The min and max are very close together, don't drag // both at one time. if ( windowX < m_xRangeMin ) { dragRight = false; } else if ( windowX > m_xRangeMax ) { dragLeft = false; } else { // We're in-between, don't drag either (top/bottom still okay) dragLeft = false; dragRight = false; } } if ( dragTop && dragBottom ) { // The min and max are very close together, don't drag // both at one time. if ( windowY < m_yRangeMin ) { dragTop = false; } else if ( windowY > m_yRangeMax ) { dragBottom = false; } else { // We're in-between, don't drag either (left/right still okay) dragTop = false; dragBottom = false; } } if ( !dragTop && !dragBottom && !dragLeft && !dragRight ) { if ( (windowX > m_xRangeMin && windowX < m_xRangeMax) && (windowY > m_yRangeMin && windowY < m_yRangeMax ) ) { dragAll = true; } } } } void TextureWidget::setDragCursor( bool dragAll, bool dragTop, bool dragBottom, bool dragLeft, bool dragRight ) { if ( !m_interactive ) { setCursor( QCursor( Qt::ArrowCursor ) ); } else if ( (dragLeft && dragTop) || (dragRight && dragBottom) ) { setCursor( QCursor( Qt::SizeFDiagCursor ) ); } else if ( (dragLeft && dragBottom) || (dragRight && dragTop) ) { setCursor( QCursor( Qt::SizeBDiagCursor ) ); } else if ( dragLeft || dragRight ) { setCursor( QCursor( Qt::SizeHorCursor ) ); } else if ( dragTop || dragBottom ) { setCursor( QCursor( Qt::SizeVerCursor ) ); } else if ( dragAll ) { setCursor( QCursor( Qt::SizeAllCursor ) ); } else { setCursor( QCursor( Qt::ArrowCursor ) ); } } void TextureWidget::clearCoordinates() { while ( m_triangles.size() ) { delete m_triangles.back(); m_triangles.pop_back(); } while ( m_vertices.size() ) { delete m_vertices.back(); m_vertices.pop_back(); } freeRotateVertices(); } void TextureWidget::getCoordinates( int tri, float * s, float * t ) { if ( !t || !s || tri >= (signed) m_triangles.size() ) { return; } for ( int v = 0; v < 3; v++ ) { s[v] = m_vertices[ m_triangles[ tri ]->vertex[v] ]->s; t[v] = m_vertices[ m_triangles[ tri ]->vertex[v] ]->t; } } void TextureWidget::saveSelectedUv() { std::vector selectedUv; for ( size_t vert = 0; vert < m_vertices.size(); ++vert ) { if ( m_vertices[ vert ]->selected ) selectedUv.push_back( vert ); } m_model->setSelectedUv( selectedUv ); } void TextureWidget::restoreSelectedUv() { std::vector selectedUv; m_model->getSelectedUv( selectedUv ); for ( size_t vert = 0; vert < m_vertices.size(); ++vert ) { m_vertices[ vert ]->selected = false; } for ( size_t vert = 0; vert < selectedUv.size(); ++vert ) { size_t v = selectedUv[vert]; if ( v < m_vertices.size() ) m_vertices[ v ]->selected = true; } } void TextureWidget::setRange( double xMin, double yMin, double xMax, double yMax ) { m_xRangeMin = xMin; m_yRangeMin = yMin; m_xRangeMax = xMax; m_yRangeMax = yMax; } void TextureWidget::getRange( double & xMin, double & yMin, double & xMax, double & yMax ) { xMin = m_xRangeMin; yMin = m_yRangeMin; xMax = m_xRangeMax; yMax = m_yRangeMax; } void TextureWidget::startScale( double x, double y ) { m_scaleList.clear(); bool first = true; double minX = 0; double minY = 0; double maxX = 0; double maxY = 0; for ( unsigned t = 0; t < m_vertices.size(); t++ ) { if ( m_vertices[t]->selected ) { // update range if ( first ) { minX = m_vertices[t]->s; minY = m_vertices[t]->t; maxX = m_vertices[t]->s; maxY = m_vertices[t]->t; first = false; } else { if ( m_vertices[t]->s < minX ) { minX = m_vertices[t]->s; }; if ( m_vertices[t]->t < minY ) { minY = m_vertices[t]->t; }; if ( m_vertices[t]->s > maxX ) { maxX = m_vertices[t]->s; }; if ( m_vertices[t]->t > maxY ) { maxY = m_vertices[t]->t; }; } ScaleVerticesT sv; sv.index = t; sv.x = m_vertices[t]->s; sv.y = m_vertices[t]->t; m_scaleList.push_back( sv ); } } if ( m_scaleFromCenter ) { m_centerX = (maxX - minX) / 2.0 + minX; m_centerY = (maxY - minY) / 2.0 + minY; m_startLengthX = fabs( m_centerX - x ); m_startLengthY = fabs( m_centerY - y ); } else { double minmin = distance( x, y, minX, minY ); double minmax = distance( x, y, minX, maxY ); double maxmin = distance( x, y, maxX, minY ); double maxmax = distance( x, y, maxX, maxY ); if ( minmin > minmax ) { if ( minmin > maxmin ) { if ( minmin > maxmax ) { m_farX = minX; m_farY = minY; } else { m_farX = maxX; m_farY = maxY; } } else // maxmin > minmin { if ( maxmin > maxmax ) { m_farX = maxX; m_farY = minY; } else { m_farX = maxX; m_farY = maxY; } } } else // minmax > minmin { if ( minmax > maxmin ) { if ( minmax > maxmax ) { m_farX = minX; m_farY = maxY; } else { m_farX = maxX; m_farY = maxY; } } else // maxmin > minmax { if ( maxmin > maxmax ) { m_farX = maxX; m_farY = minY; } else { m_farX = maxX; m_farY = maxY; } } } m_startLengthX = fabs( x - m_farX ); m_startLengthY = fabs( y - m_farY ); } } void TextureWidget::rotateSelectedVertices( double angle ) { Matrix m; Vector rot; rot[0] = 0.0; rot[1] = 0.0; rot[2] = angle; m.setRotation( rot ); double aspect = (double) this->width() / (double) this->height(); unsigned vcount = m_rotateVertices.size(); for ( unsigned v = 0; v < vcount; v++ ) { Vector vec; vec[0] = m_rotateVertices[v]->x; vec[1] = m_rotateVertices[v]->y; m.apply3( vec ); unsigned index = m_rotateVertices[v]->v; m_vertices[index]->s = (vec[0] / aspect)+ m_xRotPoint; m_vertices[index]->t = vec[1] + m_yRotPoint; } updateGL(); } void TextureWidget::scaleSelectedVertices( double x, double y ) { double spX = m_scaleFromCenter ? m_centerX : m_farX; double spY = m_scaleFromCenter ? m_centerY : m_farY; double lengthX = fabs( x - spX ); double lengthY = fabs( y - spY ); ScaleVerticesList::iterator it; for( it = m_scaleList.begin(); it != m_scaleList.end(); it++ ) { double x = (*it).x; double y = (*it).y; x -= spX; y -= spY; double xper = (lengthX / m_startLengthX); if ( m_startLengthX <= 0.00006 ) { xper = 1.0; } double yper = (lengthY / m_startLengthY); if ( m_startLengthY <= 0.00006 ) { yper = 1.0; } if ( m_scaleKeepAspect ) { if ( xper > yper ) { yper = xper; } else { xper = yper; } } x *= xper; y *= yper; x += spX; y += spY; m_vertices[(*it).index]->s = x; m_vertices[(*it).index]->t = y; } updateGL(); } void TextureWidget::freeRotateVertices() { while ( m_rotateVertices.size() ) { delete m_rotateVertices.back(); m_rotateVertices.pop_back(); } } double TextureWidget::distance( const double & x1, const double & y1, const double & x2, const double & y2 ) { double xDiff = x2 - x1; double yDiff = y2 - y1; return sqrt( xDiff*xDiff + yDiff*yDiff ); } double TextureWidget::max( const double & a, const double & b ) { return ( a > b ) ? a : b; } void TextureWidget::useLinesColor() { float b = ((m_linesColor >> 0) & 255) / 255.0; float g = ((m_linesColor >> 8) & 255) / 255.0; float r = ((m_linesColor >> 16) & 255) / 255.0; glColor3f( r, g, b ); } void TextureWidget::useSelectionColor() { float b = ((m_selectionColor >> 0) & 255) / 255.0; float g = ((m_selectionColor >> 8) & 255) / 255.0; float r = ((m_selectionColor >> 16) & 255) / 255.0; glColor3f( r, g, b ); } mm3d-master/src/depui/texwidget.h000066400000000000000000000210321324021725400172570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TEXWIDGET_H #define __TEXWIDGET_H #include #include #include #include #include #include #include class Texture; class Model; class QTimer; class TextureWidget : public QGLWidget { Q_OBJECT public: enum _DrawMode_e { DM_Edit, DM_Edges, DM_Filled, DM_FilledEdges, DM_MAX }; typedef enum _DrawMode_e DrawModeE; enum _MouseOperation_e { MouseMove, MouseSelect, MouseScale, MouseRotate, MouseRange }; typedef enum _MouseOperation_e MouseOperationE; enum _ScrollButton_e { ScrollButtonPan, ScrollButtonLeft, ScrollButtonRight, ScrollButtonUp, ScrollButtonDown, ScrollButtonMAX }; typedef enum _ScrollButton_e ScrollButtonE; struct _TextureVertex_t { double s; double t; bool selected; }; struct _RotateVertex_t { unsigned v; double x; double y; }; typedef struct _TextureVertex_t TextureVertexT; typedef std::vector< TextureVertexT * > TextureVertexVector; typedef struct _RotateVertex_t RotateVertexT; typedef std::vector< RotateVertexT * > RotateVertexVector; struct _TextureTriangle_t { int vertex[3]; }; typedef struct _TextureTriangle_t TextureTriangleT; typedef std::vector< TextureTriangleT * > TextureTriangleVector; TextureWidget( QWidget * parent = NULL ); virtual ~TextureWidget(); void setModel( Model * model ); void setTexture( int materialId, Texture * texture ); void setInteractive( bool o ); void set3d( bool o ); void setTextureCount( unsigned c ); void setSClamp( bool o ) { m_sClamp = o; setTexture( m_materialId, m_texture ); }; void setTClamp( bool o ) { m_tClamp = o; setTexture( m_materialId, m_texture ); }; void setDrawMode( DrawModeE dm ); void setDrawVertices( bool dv ) { m_drawVertices = dv; }; void setDrawBorder( bool db ) { m_drawBorder = db; }; void setMouseOperation( MouseOperationE op ); void setScaleKeepAspect( bool o ) { m_scaleKeepAspect = o; }; void setScaleFromCenter( bool o ) { m_scaleFromCenter = o; }; void setSolidBackground( bool o ) { m_solidBackground = o; }; void vFlipCoordinates(); void hFlipCoordinates(); void rotateCoordinatesCcw(); void rotateCoordinatesCw(); void setLinesColor( uint32_t newColor ) { m_linesColor = newColor; } void setSelectionColor( uint32_t newColor ) { m_selectionColor = newColor; } int addVertex( double t, double s ); int addTriangle( int v1, int v2, int v3 ); void clearCoordinates(); void getCoordinates( int tri, float * s, float * t ); void saveSelectedUv(); void restoreSelectedUv(); // This is min/max of the current viewport, not of the // vertices in the viewport double getMinViewCoord() { return m_xMin; }; double getMaxViewCoord() { return m_xMax; }; void setRange( double xMin, double yMin, double xMax, double yMax ); void getRange( double & xMin, double & yMin, double & xMax, double & yMax ); // paint my scene on another OpenGL widget void paintOnGlWidget( QGLWidget * w ); public slots: void animationTimeout(); void scrollUp(); void scrollDown(); void scrollLeft(); void scrollRight(); void zoomIn(); void zoomOut(); void scrollTimeout(); void setZoomLevel( double zoom ); signals: void updateCoordinatesSignal(); void updateSelectionDoneSignal(); void updateCoordinatesDoneSignal(); void updateRangeSignal(); void updateRangeDoneSignal(); void updateSeamSignal( double xDiff, double yDiff ); void updateSeamDoneSignal(); void zoomLevelChanged( QString zoomStr ); protected: virtual void mousePressEvent( QMouseEvent * e ); virtual void mouseReleaseEvent( QMouseEvent * e ); virtual void mouseMoveEvent( QMouseEvent * e ); virtual void wheelEvent( QWheelEvent * e ); virtual void keyPressEvent( QKeyEvent * e ); void moveSelectedVertices( double x, double y ); void updateSelectRegion( double x, double y ); void startScale( double x, double y ); void rotateSelectedVertices( double angle ); void scaleSelectedVertices( double x, double y ); void setViewportDraw(); void setViewportOverlay(); void drawTriangles(); void drawOverlay(); void makeTextureFromImage( const QImage & i, GLuint & t ); void selectDone(); void drawSelectBox(); void drawRangeBox(); void drawRotationPoint(); void clearSelected(); double getWindowXCoord( int x ); double getWindowYCoord( int y ); void updateCursorShape( int x, int y ); void getDragDirections( double x, double y, bool & all, bool & top, bool & bottom, bool & left, bool & right ); void setDragCursor( bool all, bool top, bool bottom, bool left, bool right ); void initializeGL(); void paintGL(); void resizeGL( int w, int h ); void paintInternal(); void updateViewport(); void freeRotateVertices(); double distance( const double &, const double &, const double &, const double & ); double max( const double &, const double & ); void useLinesColor(); void useSelectionColor(); int m_viewportWidth; int m_viewportHeight; bool m_sClamp; bool m_tClamp; double m_zoom; double m_xCenter; double m_yCenter; int m_lastXPos; int m_lastYPos; Model * m_model; int m_materialId; Texture * m_texture; GLuint m_glTexture; QTimer * m_scrollTimer; ScrollButtonE m_overlayButton; GLuint m_scrollTextures[2]; TextureVertexVector m_vertices; TextureTriangleVector m_triangles; RotateVertexVector m_rotateVertices; DrawModeE m_drawMode; bool m_drawVertices; bool m_drawBorder; bool m_solidBackground; MouseOperationE m_operation; bool m_scaleKeepAspect; bool m_scaleFromCenter; bool m_selecting; bool m_drawBounding; bool m_drawRange; bool m_interactive; bool m_3d; int m_button; // For 3d view QTimer * m_animTimer; double m_xMin; double m_xMax; double m_yMin; double m_yMax; // For select double m_xSel1; double m_ySel1; double m_xSel2; double m_ySel2; // For rotation double m_xRotPoint; double m_yRotPoint; double m_xRotStart; double m_yRotStart; double m_startAngle; // For projection range double m_xRangeMin; double m_yRangeMin; double m_xRangeMax; double m_yRangeMax; // For projection move/resize bool m_dragAll; bool m_dragTop; bool m_dragBottom; bool m_dragLeft; bool m_dragRight; // For scale typedef struct _ScaleVertices_t { unsigned index; double x; double y; } ScaleVerticesT; typedef std::list ScaleVerticesList; double m_farX; double m_farY; double m_centerX; double m_centerY; double m_startLengthX; double m_startLengthY; uint32_t m_linesColor; uint32_t m_selectionColor; ScaleVerticesList m_scaleList; }; #endif // __TEXWIDGET_H mm3d-master/src/icon.rc000066400000000000000000000000501324021725400152470ustar00rootroot00000000000000A ICON "src/pixmap/mm3dlogo-32x32.ico" mm3d-master/src/implui/000077500000000000000000000000001324021725400152755ustar00rootroot00000000000000mm3d-master/src/implui/Makefile.am000066400000000000000000000066261324021725400173430ustar00rootroot00000000000000 noinst_LIBRARIES = libimplui.a libimplui_HFILES = \ aboutwin.h \ alignwin.h \ animconvertwin.h \ animexportwin.h \ animsetwin.h \ animwidget.h \ animwin.h \ autoassignjointwin.h \ backgroundselect.h \ backgroundwin.h \ boolpanel.h \ boolwin.h \ cal3dprompt.h \ contextgroup.h \ contextinfluences.h \ contextname.h \ contextpanel.h \ contextposition.h \ contextprojection.h \ contextrotation.h \ extrudewin.h \ globalmenubar.h \ groupclean.h \ groupwin.h \ helpwin.h \ jointwin.h \ keycfg.h \ keyvaluewin.h \ licensewin.h \ mapdirection.h \ mergewin.h \ metawin.h \ ms3dprompt.h \ msgqt.h \ mview.h \ newanim.h \ objprompt.h \ painttexturewin.h \ paintwidget.h \ pluginwin.h \ pointwin.h \ projectionwin.h \ qtmain.h \ qttex.h \ rgbawin.h \ spherifywin.h \ statusbar.h \ texturecoord.h \ texwin.h \ transformwin.h \ transimp.h \ valuewin.h \ viewpanel.h \ viewportsettings.h \ viewwin.h libimplui_MOC = \ aboutwin.moc.cc \ alignwin.moc.cc \ animconvertwin.moc.cc \ animexportwin.moc.cc \ animsetwin.moc.cc \ animwidget.moc.cc \ animwin.moc.cc \ autoassignjointwin.moc.cc \ backgroundselect.moc.cc \ backgroundwin.moc.cc \ boolpanel.moc.cc \ boolwin.moc.cc \ cal3dprompt.moc.cc \ contextgroup.moc.cc \ contextinfluences.moc.cc \ contextname.moc.cc \ contextpanel.moc.cc \ contextposition.moc.cc \ contextprojection.moc.cc \ contextrotation.moc.cc \ extrudewin.moc.cc \ globalmenubar.moc.cc \ groupclean.moc.cc \ groupwin.moc.cc \ helpwin.moc.cc \ jointwin.moc.cc \ pointwin.moc.cc \ painttexturewin.moc.cc \ projectionwin.moc.cc \ keyvaluewin.moc.cc \ licensewin.moc.cc \ mergewin.moc.cc \ metawin.moc.cc \ ms3dprompt.moc.cc \ mview.moc.cc \ newanim.moc.cc \ objprompt.moc.cc \ pluginwin.moc.cc \ rgbawin.moc.cc \ spherifywin.moc.cc \ statusbar.moc.cc \ texturecoord.moc.cc \ texwin.moc.cc \ transformwin.moc.cc \ valuewin.moc.cc \ viewportsettings.moc.cc \ viewpanel.moc.cc \ viewwin.moc.cc BUILT_SOURCES = $(libimplui_MOC) libimplui_a_SOURCES = \ aboutwin.cc \ alignwin.cc \ animconvertwin.cc \ animexportwin.cc \ animsetwin.cc \ animwidget.cc \ animwin.cc \ autoassignjointwin.cc \ backgroundselect.cc \ backgroundwin.cc \ boolpanel.cc \ boolwin.cc \ cal3dprompt.cc \ contextgroup.cc \ contextinfluences.cc \ contextname.cc \ contextpanel.cc \ contextposition.cc \ contextprojection.cc \ contextrotation.cc \ extrudewin.cc \ globalmenubar.cc \ groupclean.cc \ groupwin.cc \ helpwin.cc \ jointwin.cc \ keycfg.cc \ keyvaluewin.cc \ licensewin.cc \ mapdirection.cc \ mergewin.cc \ metawin.cc \ ms3dprompt.cc \ msgqt.cc \ mview.cc \ newanim.cc \ objprompt.cc \ painttexturewin.cc \ paintwidget.cc \ pluginwin.cc \ pointwin.cc \ projectionwin.cc \ qtmain.cc \ qttex.cc \ rgbawin.cc \ spherifywin.cc \ statusbar.cc \ texturecoord.cc \ texwin.cc \ transformwin.cc \ transimp.cc \ valuewin.cc \ viewpanel.cc \ viewportsettings.cc \ viewwin.cc \ viewwin_influences.cc \ $(libimplui_MOC) \ $(libimplui_HFILES) %.moc.cc: %.h $(QT_MOC) -o $@ $< %.base.h: %.ui $(QT_UIC) -o $@ $*.ui %.base.cc: $(mm3d_UIHEADERS) %.ui $(QT_UIC) -o $@ -impl $*.base.h $*.ui # -DQT_NO_CAST_ASCII AM_CPPFLAGS = $(PROFILE) $(COVFLAGS) -Wall -I../libmm3d -I../mm3dcore -I../depui -I../qtui -I../ -DMM3D_EDIT $(all_includes) $(QT_CXXFLAGS) $(LUALIB_CCFLAGS) $(GL_CFLAGS) CLEANFILES = $(libimplui_MOC) $(mm3d_UIHEADERS) *.gcno *.gcda mm3d-master/src/implui/aboutwin.cc000066400000000000000000000031011324021725400174270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "aboutwin.h" #include "version.h" #include #define ABOUT_TEXT "Misfit Model 3D - About " \ "

" \ "

Misfit Model 3D

" \ "

" VERSION_STRING "


" \ "Copyright © 2004-2008, Kevin Worcester
" \ "clover.moe fork © 2009-2018 Zack Middleton

" \ "https://clover.moe/mm3d
" \ "
" AboutWin::AboutWin( QWidget * parent ) : QDialog( parent ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( false ); setWindowTitle( tr( "Misfit Model 3D - About") ); resize( 350, 300 ); m_text->setHtml( QString( ABOUT_TEXT ) ); } AboutWin::~AboutWin() { } mm3d-master/src/implui/aboutwin.h000066400000000000000000000022011324021725400172710ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ABOUTWIN_H #define __ABOUTWIN_H #include "textwin.base.h" #include class AboutWin : public QDialog, public Ui::TextWinBase { Q_OBJECT public: AboutWin( QWidget * parent = NULL ); virtual ~AboutWin(); protected: }; #endif // __ABOUTWIN_H mm3d-master/src/implui/alignwin.cc000066400000000000000000000067471324021725400174320ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "alignwin.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include using std::list; using std::map; AlignWin::AlignWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ), m_atX( AT_Center ), m_atY( AT_Center ), m_atZ( AT_Center ) { setAttribute( Qt::WA_DeleteOnClose ); setModal( true ); setupUi( this ); m_xCenter->setChecked( true ); m_yCenter->setChecked( true ); m_zCenter->setChecked( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } AlignWin::~AlignWin() { } void AlignWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_alignwin.html", true ); win->show(); } void AlignWin::alignX() { double val = m_xValue->text().toDouble(); log_debug( "aligning x on %f\n", val ); alignSelectedX( m_model, m_atX, val ); DecalManager::getInstance()->modelUpdated( m_model ); model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Align X").toUtf8() ); } void AlignWin::alignY() { double val = m_yValue->text().toDouble(); log_debug( "aligning y on %f\n", val ); alignSelectedY( m_model, m_atY, val ); DecalManager::getInstance()->modelUpdated( m_model ); model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Align Y").toUtf8() ); } void AlignWin::alignZ() { double val = m_zValue->text().toDouble(); log_debug( "aligning z on %f\n", val ); alignSelectedZ( m_model, m_atZ, val ); DecalManager::getInstance()->modelUpdated( m_model ); model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Align Z").toUtf8() ); } void AlignWin::selectedXCenter() { m_atX = AT_Center; } void AlignWin::selectedXMin() { m_atX = AT_Min; } void AlignWin::selectedXMax() { m_atX = AT_Max; } void AlignWin::selectedYCenter() { m_atY = AT_Center; } void AlignWin::selectedYMin() { m_atY = AT_Min; } void AlignWin::selectedYMax() { m_atY = AT_Max; } void AlignWin::selectedZCenter() { m_atZ = AT_Center; } void AlignWin::selectedZMin() { m_atZ = AT_Min; } void AlignWin::selectedZMax() { m_atZ = AT_Max; } void AlignWin::accept() { log_debug( "Alignment complete\n" ); m_model->operationComplete( tr( "Align Selected", "operation complete" ).toUtf8() ); QDialog::accept(); } void AlignWin::reject() { log_debug( "Alignment canceled\n" ); m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/alignwin.h000066400000000000000000000034441324021725400172630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ALIGNWIN_H #define __ALIGNWIN_H #include "alignwin.base.h" #include "align.h" #include class Model; class AlignWin : public QDialog, public Ui::AlignWinBase { Q_OBJECT public: AlignWin( Model *, QWidget * parent = NULL ); virtual ~AlignWin(); public slots: void alignX(); void alignY(); void alignZ(); void selectedXCenter(); void selectedXMin(); void selectedXMax(); void selectedYCenter(); void selectedYMin(); void selectedYMax(); void selectedZCenter(); void selectedZMin(); void selectedZMax(); void accept(); void reject(); void helpNowEvent(); protected: Model * m_model; double m_xMin; double m_xMax; double m_yMin; double m_yMax; double m_zMin; double m_zMax; AlignTypeE m_atX; AlignTypeE m_atY; AlignTypeE m_atZ; }; #endif // __ALIGNWIN_H mm3d-master/src/implui/animconvertwin.cc000066400000000000000000000056441324021725400206600ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "animconvertwin.h" #include "helpwin.h" #include #include #include #include #include AnimConvertWindow::AnimConvertWindow( QWidget * parent ) : QDialog( parent ), m_operation( OP_CONTINUE ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } AnimConvertWindow::~AnimConvertWindow() { } void AnimConvertWindow::setAnimationData( Model * model, Model::AnimationModeE mode, unsigned animIndex ) { switch ( mode ) { case Model::ANIMMODE_SKELETAL: m_convertLabel->setText( tr( "Convert Skeletal to Frame:" ) ); break; case Model::ANIMMODE_FRAME: m_convertLabel->setText( tr( "Convert Frame to Frame:" ) ); break; case Model::ANIMMODE_FRAMERELATIVE: m_convertLabel->setText( tr( "Convert Frame Relative to Frame:" ) ); break; default: m_convertLabel->setText( tr( "Convert Unknown Type to Frame:" ) ); break; } const char * name = model->getAnimName( mode, animIndex ); m_origName->setText( QString::fromUtf8( name ) ); m_newName->setText( QString::fromUtf8( name ) ); m_newFrameCount->setValue( model->getAnimFrameCount( mode, animIndex ) ); m_origName->setFocus(); } QString AnimConvertWindow::getNewName() { return m_newName->text(); } unsigned AnimConvertWindow::getNewFrameCount() { return m_newFrameCount->value(); } AnimConvertWindow::OperationE AnimConvertWindow::requestedOperation() { return m_operation; } void AnimConvertWindow::continueClicked() { m_operation = OP_CONTINUE; accept(); } void AnimConvertWindow::cancelClicked() { m_operation = OP_CANCEL; reject(); } void AnimConvertWindow::cancelAllClicked() { m_operation = OP_CANCEL_ALL; reject(); } void AnimConvertWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_animconvertwin.html", true ); win->show(); } mm3d-master/src/implui/animconvertwin.h000066400000000000000000000033741324021725400205200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ANIMCONVERTWIN_H #define __ANIMCONVERTWIN_H #include "animconvertwin.base.h" #include "model.h" #include class Q3Accel; class AnimConvertWindow : public QDialog, public Ui::AnimConvertWinBase { Q_OBJECT public: enum _Operation_e { OP_CONTINUE, OP_CANCEL, OP_CANCEL_ALL }; typedef enum _Operation_e OperationE; AnimConvertWindow( QWidget * parent = NULL ); virtual ~AnimConvertWindow(); void setAnimationData( Model * model, Model::AnimationModeE mode, unsigned animIndex ); QString getNewName(); unsigned getNewFrameCount(); OperationE requestedOperation(); public slots: void helpNowEvent(); void continueClicked(); void cancelClicked(); void cancelAllClicked(); protected: Q3Accel * m_accel; OperationE m_operation; }; #endif // __ANIMCONVERTWIN_H mm3d-master/src/implui/animexportwin.cc000066400000000000000000000216741324021725400205220ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "animexportwin.h" #include "helpwin.h" #include "viewpanel.h" #include "model.h" #include "mview.h" #include "3dmprefs.h" #include "misc.h" #include "texture.h" #include "texmgr.h" #include "msg.h" #include "mm3dport.h" #include #include #include #include #include #include #include #include #include #include #include AnimExportWindow::AnimExportWindow( Model * model, ViewPanel * viewPanel, QWidget * parent ) : QDialog( parent ), m_model( model ), m_viewPanel( viewPanel ) { setModal( true ); setupUi( this ); QString path = QString::fromUtf8( g_prefs( "ui_animexport_dir" ).stringValue().c_str() ); if ( g_prefs.exists( "ui_animexport_format" ) ) { int f = g_prefs( "ui_animexport_format" ).intValue(); if ( f >= 0 && f < m_formatValue->count() ) { m_formatValue->setCurrentIndex( f ); } } if ( g_prefs.exists( "ui_animexport_framerate" ) ) { double fps = g_prefs( "ui_animexport_framerate" ).doubleValue(); if ( fps > 0.0001 ) { char fpsStr[20] = ""; PORT_snprintf( fpsStr, sizeof(fpsStr), "%f", fps ); m_frameRateValue->setText( QString(fpsStr) ); } } if ( g_prefs.exists( "ui_animexport_seconds" ) ) { int sec = g_prefs( "ui_animexport_seconds" ).intValue(); if ( sec > 0 ) { char secStr[20] = ""; PORT_snprintf( secStr, sizeof(secStr), "%d", sec ); m_secondsValue->setText( QString(secStr) ); } } if ( g_prefs.exists( "ui_animexport_iterations" ) ) { int iterations = g_prefs( "ui_animexport_iterations" ).intValue(); if ( iterations > 0 ) { char itStr[20] = ""; PORT_snprintf( itStr, sizeof(itStr), "%d", iterations ); m_iterationsValue->setText( QString(itStr) ); } } if ( m_model ) { bool labelAnims = false; unsigned scount = m_model->getAnimCount( Model::ANIMMODE_SKELETAL ); unsigned fcount = m_model->getAnimCount( Model::ANIMMODE_FRAME ); if ( scount > 0 && fcount > 0 ) { labelAnims = true; } unsigned a = 0; for ( a = 0; a < scount; a++ ) { QString name = labelAnims ? tr( "Skeletal - ", "Skeletal Animation prefix" ) : QString(""); name += m_model->getAnimName( Model::ANIMMODE_SKELETAL, a ); m_animValue->insertItem( a, name ); } for ( a = 0; a < fcount; a++ ) { QString name = labelAnims ? tr( "Frame - ", "Frame Animation prefix" ) : QString(""); name += m_model->getAnimName( Model::ANIMMODE_FRAME, a ); m_animValue->insertItem( scount + a, name ); } const char * filename = m_model->getFilename(); if ( path.isNull() || path.isEmpty() ) { std::string fullName = ""; std::string fullPath = ""; std::string baseName = ""; normalizePath( filename, fullName, fullPath, baseName ); if ( is_directory( fullPath.c_str() ) ) { path = fullPath.c_str(); } } } if ( path.isNull() || path.isEmpty() ) { char cwd[ PATH_MAX ] = "/"; //#ifdef WIN32 // _getcwd( cwd, sizeof( cwd ) ); //#else getcwd( cwd, sizeof( cwd ) ); //#endif path = cwd; } m_directoryLabel->setText( path ); if ( m_viewPanel ) { int index = -1; unsigned count = m_viewPanel->getModelViewCount(); for ( unsigned m = 0; m < count; m++ ) { ModelView * v = m_viewPanel->getModelView( m ); QString name = tr( "[None]", "No viewport for animation image export" ); if ( v ) { name = tr("Viewport %1 - ").arg(m+1); name += v->getViewDirectionLabel(); if ( index == -1 && v->getViewDirection() == 0 ) { index = m; } } m_viewportValue->insertItem( m, name ); } if ( index >= 0 ) { m_viewportValue->setCurrentIndex( index ); } } QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } AnimExportWindow::~AnimExportWindow() { } void AnimExportWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_animexportwin.html", true ); win->show(); } void AnimExportWindow::accept() { if ( m_viewPanel == NULL || m_model == NULL ) { return; } ModelView * v = m_viewPanel->getModelView( m_viewportValue->currentIndex() ); if ( v == NULL ) { return; } Model::AnimationModeE mode = Model::ANIMMODE_SKELETAL; unsigned a = m_animValue->currentIndex(); if ( a >= m_model->getAnimCount( mode ) ) { a -= m_model->getAnimCount( mode ); mode = Model::ANIMMODE_FRAME; } double fps = m_model->getAnimFPS( mode, a ); double spf = ( 1.0 / fps ); double duration = 0.0; double tm = 0.0; double outfps = m_frameRateValue->text().toDouble(); if ( outfps < 0.0001 ) { msg_warning( (const char *) tr("Must have more than 0 frames per second").toUtf8() ); return; } double interval = (1.0 / outfps); if ( m_timeButton->isChecked() ) { duration = m_secondsValue->text().toDouble(); } else { duration = spf * m_iterationsValue->text().toInt() * m_model->getAnimFrameCount( mode, a ); } if ( duration <= 0.0 ) { msg_warning( (const char *) tr("Must have more than 0 seconds of animation").toUtf8() ); return; } QString path = m_directoryLabel->text(); if ( is_directory( path.toUtf8() ) ) { g_prefs( "ui_animexport_dir" ) = (const char *) path.toUtf8(); g_prefs( "ui_animexport_format" ) = m_formatValue->currentIndex(); g_prefs( "ui_animexport_framerate" ) = m_frameRateValue->text().toDouble(); g_prefs( "ui_animexport_seconds" ) = m_secondsValue->text().toInt(); g_prefs( "ui_animexport_iterations" ) = m_iterationsValue->text().toInt(); bool enable = m_model->setUndoEnabled( false ); m_model->setCurrentAnimation( mode, a ); int frameNum = 0; char formatStr[20] = ""; QString saveFormat = QString( "JPEG" ); switch ( m_formatValue->currentIndex() ) { case 0: strcpy( formatStr, "%s/anim_%04d.jpg" ); break; case 1: strcpy( formatStr, "%s/anim_%d.jpg" ); break; case 2: strcpy( formatStr, "%s/anim_%04d.png" ); saveFormat = QString( "PNG" ); break; case 3: default: strcpy( formatStr, "%s/anim_%d.png" ); saveFormat = QString( "PNG" ); break; } this->hide(); bool prompt = true; bool keepGoing = true; while ( keepGoing && tm <= duration ) { m_model->setCurrentAnimationTime( tm ); v->updateCaptureGL(); frameNum++; QString file; file.sprintf( formatStr, (const char *) path.toUtf8(), frameNum ); QImage img = v->grabFrameBuffer( false ); if ( !img.save( file, saveFormat.toUtf8(), 100 ) && prompt ) { QString msg = tr( "Could not write file: " ) + QString("\n"); msg += file; msg_error( (const char *) msg.toUtf8() ); keepGoing = false; } tm += interval; } m_model->setNoAnimation(); m_model->setUndoEnabled( enable ); v->updateView(); QDialog::accept(); } else { msg_warning( (const char *) tr("Output directory does not exist.").toUtf8() ); } } void AnimExportWindow::reject() { QDialog::reject(); } void AnimExportWindow::directoryButtonClicked() { QString dir = QFileDialog::getExistingDirectory( this, "Select an output directory", m_directoryLabel->text() ); if ( ! dir.isNull() && ! dir.isEmpty() ) { m_directoryLabel->setText( dir ); } } mm3d-master/src/implui/animexportwin.h000066400000000000000000000027001324021725400203510ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ANIMEXPORTWIN_H #define __ANIMEXPORTWIN_H #include "animexportwin.base.h" #include "model.h" #include class ViewPanel; class Model; class AnimExportWindow : public QDialog, public Ui::AnimExportWinBase { Q_OBJECT public: AnimExportWindow( Model * model, ViewPanel * viewPanel, QWidget * parent = NULL ); virtual ~AnimExportWindow(); public slots: void helpNowEvent(); void accept(); void reject(); void directoryButtonClicked(); protected: Model * m_model; ViewPanel * m_viewPanel; }; #endif // __ANIMEXPORTWIN_H mm3d-master/src/implui/animsetwin.cc000066400000000000000000000402411324021725400177630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "animsetwin.h" #include "animconvertwin.h" #include "decalmgr.h" #include "log.h" #include "msg.h" #include "helpwin.h" #include #include #include #include #include #include using std::list; AnimSetWindow::AnimSetWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setupUi( this ); setModal( true ); m_animType->insertItem( 0, tr( "Skeletal Animation" ) ); m_animType->insertItem( 1, tr( "Frame Animation" ) ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); unsigned skelCount = m_model->getAnimCount( Model::ANIMMODE_SKELETAL ); unsigned frameCount = m_model->getAnimCount( Model::ANIMMODE_FRAME ); unsigned relativeCount = m_model->getAnimCount( Model::ANIMMODE_FRAMERELATIVE ); if ( skelCount > 0 ) { m_animType->setCurrentIndex(0); } else if ( frameCount > 0 ) { m_animType->setCurrentIndex(2); } else if ( relativeCount > 0 ) { m_animType->setCurrentIndex(2); } else { m_animType->setCurrentIndex(0); } fillAnimationList(); animModeSelected( m_animType->currentIndex() ); //Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); } AnimSetWindow::~AnimSetWindow() { } void AnimSetWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_animsetwin.html", true ); win->show(); } void AnimSetWindow::animModeSelected( int index ) { switch( index ) { case 0: m_convertButton->setEnabled( true ); m_mergeButton->setEnabled( true ); break; case 1: m_convertButton->setEnabled( false ); m_mergeButton->setEnabled( false ); break; case 2: m_convertButton->setEnabled( true ); m_mergeButton->setEnabled( false ); break; default: break; } fillAnimationList(); } void AnimSetWindow::upClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); unsigned count = m_animList->count(); unsigned t = 0; for ( t = 0; t < count && m_animList->item(t)->isSelected(); t++ ) { // do nothing (loop finds first unselected item) } unsigned lastUnselected = t; bool moving = false; // t is initialized above for ( ; t < count; t++ ) { if ( moving ) { if ( ! m_animList->item(t)->isSelected() ) { unsigned oldIndex = lastUnselected; unsigned newIndex = t - 1; m_model->moveAnimation( mode, oldIndex, newIndex ); moving = false; QListWidgetItem * item = m_animList->takeItem( oldIndex ); m_animList->insertItem( newIndex, item ); log_debug( "moved item from %d to %d\n", oldIndex, newIndex ); lastUnselected = newIndex; t = newIndex; } } else { if ( m_animList->item(t)->isSelected() ) { moving = true; } else { lastUnselected = t; } } } if ( moving ) { unsigned newIndex = count - 1; m_model->moveAnimation( mode, lastUnselected, newIndex ); QListWidgetItem * item = m_animList->takeItem( lastUnselected ); m_animList->insertItem( newIndex, item ); log_debug( "moved item from %d to %d\n", lastUnselected, newIndex ); } } void AnimSetWindow::downClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); unsigned count = m_animList->count(); int t = 0; for ( t = count - 1; t >= 0 && m_animList->item(t)->isSelected(); t-- ) { // do nothing (loop finds first unselected item) } unsigned lastUnselected = t; bool moving = false; // t is initialized above for ( ; t >= 0; t-- ) { if ( moving ) { if ( ! m_animList->item(t)->isSelected() ) { unsigned oldIndex = lastUnselected; unsigned newIndex = t + 1; m_model->moveAnimation( mode, oldIndex, newIndex ); moving = false; QListWidgetItem * item = m_animList->takeItem( oldIndex ); m_animList->insertItem( newIndex, item ); log_debug( "moved item from %d to %d\n", oldIndex, newIndex ); lastUnselected = newIndex; t = newIndex; } } else { if ( m_animList->item(t)->isSelected() ) { moving = true; } else { lastUnselected = t; } } } if ( moving ) { unsigned newIndex = 0; m_model->moveAnimation( mode, lastUnselected, newIndex ); QListWidgetItem * item = m_animList->takeItem( lastUnselected ); m_animList->insertItem( newIndex, item ); log_debug( "moved item from %d to %d\n", lastUnselected, newIndex ); } } void AnimSetWindow::newClicked() { bool ok = false; QString name = QInputDialog::getText( this, tr( "Misfit 3D" ), tr( "New name:" ), QLineEdit::Normal, QString(""), &ok ); if ( ok && !name.isEmpty() ) { int num = m_model->addAnimation( indexToMode( m_animType->currentIndex() ), name.toUtf8() ); if ( num >= 0 ) { m_animList->insertItem( num, name ); m_animList->setCurrentItem(m_animList->item(num)); m_animList->clearSelection(); m_animList->item(num)->setSelected( true ); } } } void AnimSetWindow::renameClicked() { bool isSelection = false; unsigned firstSelection = 0; unsigned count = m_animList->count(); for ( firstSelection = 0; firstSelection < count; firstSelection++ ) { if ( m_animList->item(firstSelection)->isSelected() ) { isSelection = true; break; } } if ( isSelection ) { bool ok = false; QString name = QInputDialog::getText( this, tr( "Misfit 3D" ), tr( "New name:" ), QLineEdit::Normal, m_animList->item( firstSelection )->text(), &ok ); if ( ok && !name.isEmpty() ) { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); for ( unsigned t = 0; t < count; t++ ) { if ( m_animList->item(t)->isSelected() ) { m_model->setAnimName( mode, t, name.toUtf8() ); m_animList->item(t)->setText( name ); } } } } } void AnimSetWindow::deleteClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); unsigned count = m_animList->count(); unsigned lastDeleted = 0; bool refillList = false; for ( int t = count - 1; t >= 0; t-- ) { if ( m_animList->item(t)->isSelected() ) { m_model->deleteAnimation( mode, t ); refillList = true; lastDeleted = t; } } if ( refillList ) { fillAnimationList(); count = m_animList->count(); for ( unsigned int t = 0; t < count; ++t ) { m_animList->item(t)->setSelected( false ); } if ( count > 0 ) { if ( lastDeleted < count ) { m_animList->setCurrentItem(m_animList->item(lastDeleted)); } else { m_animList->setCurrentItem(m_animList->item(count - 1)); } } } } void AnimSetWindow::copyClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); list newAnims; unsigned count = m_animList->count(); for ( unsigned t = 0; t < count; t++ ) { if ( m_animList->item(t)->isSelected() ) { QString name = m_animList->item( t )->text(); name += QString( " " ) + tr( "copy" ); int num = m_model->copyAnimation( mode, t, name.toUtf8() ); if ( num >= 0 ) { newAnims.push_back( num ); } } } if ( !newAnims.empty() ) { fillAnimationList(); list::iterator it; m_animList->setCurrentItem(m_animList->item(newAnims.back())); count = m_animList->count(); for ( unsigned int t = 0; t < count; ++t ) { m_animList->item(t)->setSelected( false ); } for ( it = newAnims.begin(); it != newAnims.end(); it++ ) { m_animList->item( *it )->setSelected( true ); } } } void AnimSetWindow::splitClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); unsigned count = m_animList->count(); bool refillList = false; int splitNum = 0; for ( int t = count - 1; t >= 0; t-- ) { if ( m_animList->item(t)->isSelected() ) { splitNum = t; if ( m_model->getAnimFrameCount( mode, t ) >= 2 ) { bool ok = false; QString name = QString::fromUtf8( m_model->getAnimName( mode, t ) ); unsigned frame = QInputDialog::getInt( this, tr("Split at frame", "Split animation frame window title" ), tr("Split", "'Split' refers to splitting an animation into two separate animations" ) + QString(" ") + name + QString(" ") + tr("at frame number", "the frame number where the second (split) animation begins" ), 2, 2, m_model->getAnimFrameCount( mode, t ), 1, &ok ); if ( ok ) { name = name + " " + tr("split"); if ( m_model->splitAnimation( mode, t, name.toUtf8(), frame ) ) { refillList = true; } } } else { QMessageBox::information( this, tr("Cannot Split", "Cannot split animation window title"), tr("Must have at least 2 frames to split", "split animation" ), QMessageBox::Ok ); } } } if ( refillList ) { fillAnimationList(); m_animList->setCurrentItem(m_animList->item(splitNum)); count = m_animList->count(); for ( unsigned int t = 0; t < count; ++t ) { m_animList->item(t)->setSelected( false ); } m_animList->item( splitNum )->setSelected( true ); } } void AnimSetWindow::joinClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); unsigned count = m_animList->count(); int joinNum = -1; bool joined = false; unsigned currentAnim = 0; // indices change, need this to keep track of real index for ( unsigned t = 0; t < count; t++ ) { if ( m_animList->item(t)->isSelected() ) { if ( joinNum >= 0 ) { log_debug( "joining %d to %d\n", t, joinNum ); m_model->joinAnimations( mode, joinNum, currentAnim ); joined = true; } else { log_debug( "animation to join to is %d\n" ); joinNum = t; currentAnim++; } } else { currentAnim++; } } if ( joined ) { fillAnimationList(); m_animList->setCurrentItem(m_animList->item(joinNum)); count = m_animList->count(); for ( unsigned int t = 0; t < count; ++t ) { m_animList->item(t)->setSelected( false ); } m_animList->item( joinNum )->setSelected( true ); } } void AnimSetWindow::mergeClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); if ( mode == Model::ANIMMODE_SKELETAL ) { unsigned count = m_animList->count(); int mergeNum = -1; bool merged = false; unsigned currentAnim = 0; // indices change, need this to keep track of real index for ( unsigned t = 0; t < count; t++ ) { if ( m_animList->item(t)->isSelected() ) { if ( mergeNum >= 0 ) { unsigned fc1 = m_model->getAnimFrameCount( mode, mergeNum ); unsigned fc2 = m_model->getAnimFrameCount( mode, currentAnim ); if ( fc1 == fc2 ) { log_debug( "merging %d to %d\n", t, mergeNum ); m_model->mergeAnimations( mode, mergeNum, currentAnim ); merged = true; } else { QString str; str = tr("Cannot merge animation %1 and %2,\n frame counts differ.") .arg(m_model->getAnimName( mode, mergeNum )) .arg(m_model->getAnimName( mode, currentAnim )); msg_error( (const char *) str.toUtf8() ); } } else { log_debug( "animation to merge to is %d\n" ); mergeNum = t; currentAnim++; } } else { currentAnim++; } } if ( merged ) { fillAnimationList(); m_animList->setCurrentItem(m_animList->item(mergeNum)); count = m_animList->count(); for ( unsigned int t = 0; t < count; ++t ) { m_animList->item(t)->setSelected( false ); } m_animList->item( mergeNum )->setSelected( true ); } } else { msg_error( (const char *) tr("Can only merge skeletal animations.").toUtf8() ); } } void AnimSetWindow::convertClicked() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); bool cancelled = false; unsigned count = m_animList->count(); for ( unsigned t = 0; !cancelled && t < count; t++ ) { if ( m_animList->item(t)->isSelected() ) { AnimConvertWindow acw( this ); acw.setAnimationData( m_model, mode, t ); acw.exec(); switch ( acw.requestedOperation() ) { case AnimConvertWindow::OP_CONTINUE: { QString name = acw.getNewName(); unsigned frameCount = acw.getNewFrameCount(); m_model->convertAnimToFrame( mode, t, name.toUtf8(), frameCount ); } break; case AnimConvertWindow::OP_CANCEL: break; case AnimConvertWindow::OP_CANCEL_ALL: cancelled = true; break; } } } } void AnimSetWindow::accept() { m_model->operationComplete( tr( "Animation changes", "operation complete" ).toUtf8() ); QDialog::accept(); } void AnimSetWindow::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } void AnimSetWindow::fillAnimationList() { Model::AnimationModeE mode = indexToMode( m_animType->currentIndex() ); m_animList->clear(); unsigned count = m_model->getAnimCount( mode ); for ( unsigned t = 0; t < count; t++ ) { m_animList->insertItem( t, QString::fromUtf8( m_model->getAnimName( mode, t ) ) ); } if ( count > 0 ) { m_animList->setCurrentItem(m_animList->item(0)); } } Model::AnimationModeE AnimSetWindow::indexToMode( int index ) { Model::AnimationModeE mode = Model::ANIMMODE_SKELETAL; switch( index ) { case 0: mode = Model::ANIMMODE_SKELETAL; break; case 1: mode = Model::ANIMMODE_FRAME; break; case 2: mode = Model::ANIMMODE_FRAMERELATIVE; break; default: break; } return mode; } mm3d-master/src/implui/animsetwin.h000066400000000000000000000033001324021725400176200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ANIMSETWIN_H #define __ANIMSETWIN_H #include "animsetwin.base.h" #include "model.h" #include class AnimSetWindow : public QDialog, public Ui::AnimSetWinBase { Q_OBJECT public: AnimSetWindow( Model * model, QWidget * parent = NULL ); virtual ~AnimSetWindow(); public slots: void helpNowEvent(); void animModeSelected( int index ); void upClicked(); void downClicked(); void newClicked(); void renameClicked(); void deleteClicked(); void copyClicked(); void splitClicked(); void joinClicked(); void mergeClicked(); void convertClicked(); void accept(); void reject(); protected: void fillAnimationList(); Model::AnimationModeE indexToMode( int index ); Model * m_model; }; #endif // __ANIMSETWIN_H mm3d-master/src/implui/animwidget.cc000066400000000000000000000531121324021725400177360ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "animwidget.h" #include "decalmgr.h" #include "log.h" #include "msg.h" #include "newanim.h" #include "3dmprefs.h" #include "helpwin.h" #include #include #include #include #include #include #include #include #include #include #include enum { ANIMWIN_HELP_ID, ANIMWIN_UNDO_ID, ANIMWIN_REDO_ID }; static int getSliderTickInterval( int val ) { if ( val > 25000 ) { return 5000; } if ( val > 10000 ) { return 1000; } if ( val > 2500 ) { return 500; } if ( val > 1000 ) { return 100; } if ( val > 250 ) { return 50; } if ( val > 100 ) { return 10; } if ( val > 25 ) { return 5; } return 1; } AnimWidget::AnimWidget( Model * model, bool isUndo, QWidget * parent ) : QWidget( parent ), m_model( model ), m_playing( false ), m_undoing( isUndo ), m_ignoreChange( false ) { setupUi( this ); log_debug( "AnimWidget constructor\n" ); m_animTimer = new QTimer( this ); connect( m_animTimer, SIGNAL(timeout()), this, SLOT(timeElapsed()) ); initialize( model, isUndo ); } AnimWidget::~AnimWidget() { } void AnimWidget::initialize( Model * model, bool isUndo ) { m_needShutdown = true; m_model = model; m_animName->clear(); //m_skelNew->setDefault( false ); m_countSlider->setTickPosition( QSlider::TicksBelow ); m_loop->setChecked( m_model->getAnimationLooping(m_model->getAnimationMode(), m_model->getCurrentAnimation()) ); m_skelAnimCount = m_model->getAnimCount( Model::ANIMMODE_SKELETAL ); m_frameAnimCount = m_model->getAnimCount( Model::ANIMMODE_FRAME ); m_animCount = m_skelAnimCount + m_frameAnimCount; insertAnimationNames(); if ( isUndo ) { Model::AnimationModeE mode = m_model->getAnimationMode(); if ( !mode ) { if ( m_skelAnimCount > 0 ) { mode = Model::ANIMMODE_SKELETAL; m_model->setCurrentAnimation( mode, (unsigned int) 0 ); } else if ( m_frameAnimCount > 0 ) { mode = Model::ANIMMODE_FRAME; m_model->setCurrentAnimation( mode, (unsigned int) 0 ); } } unsigned anim = m_model->getCurrentAnimation(); unsigned frame = m_model->getCurrentAnimationFrame(); m_model->setCurrentAnimation( mode, anim ); m_model->setCurrentAnimationFrame( frame ); m_animName->setCurrentIndex( animToIndex( mode, anim ) ); m_undoing = false; m_currentAnim = anim; m_currentFrame = frame; m_mode = mode; refreshPage(); } else { m_mode = Model::ANIMMODE_SKELETAL; if ( m_skelAnimCount > 0 ) { m_model->setCurrentAnimation( m_mode, indexToAnim( m_animName->currentIndex() ) ); } else if ( m_frameAnimCount > 0 ) { m_mode = Model::ANIMMODE_FRAME; m_model->setCurrentAnimation( m_mode, indexToAnim( m_animName->currentIndex() ) ); } m_model->setCurrentAnimationFrame( 0 ); refreshPage(); m_model->operationComplete( tr( "Start animation mode", "operation complete" ).toUtf8() ); } m_stop->setEnabled( false ); } void AnimWidget::nameSelected( int index ) { log_debug( "anim name selected: %d\n", index ); if ( !m_ignoreChange && index >= (int) m_animCount ) { NewAnim win( this ); g_prefs.setDefault( "ui_new_anim_type", 0 ); win.setSkeletal( g_prefs( "ui_new_anim_type" ).intValue() == 0 ); if ( win.exec() ) { stopClicked(); g_prefs( "ui_new_anim_type" ) = win.isSkeletal() ? 0 : 1; QString name = win.getAnimName(); Model::AnimationModeE mode = win.isSkeletal() ? Model::ANIMMODE_SKELETAL : Model::ANIMMODE_FRAME; int anim = m_model->addAnimation( mode, name.toUtf8() ); m_model->setCurrentAnimation( mode, anim ); m_model->operationComplete( tr( "New Animation", "operation complete" ).toUtf8() ); initialize( m_model, true ); return; } else { if ( m_animCount > 0 ) { index = animToIndex( m_mode, m_currentAnim ); m_animName->setCurrentIndex( index ); } else { return; } } } m_currentTime = 0; m_mode = indexToMode( index ); index = indexToAnim( index ); m_currentAnim = index; m_currentFrame = 0; if( index < (int) m_animCount ) { m_model->setCurrentAnimation( m_mode, m_currentAnim ); if ( m_playing ) { // Re-initialize time interval based on new anim's FPS. doPlay(); } } else { m_model->setCurrentAnimation( m_mode, (unsigned) 0 ); } refreshPage(); } void AnimWidget::setCurrentFrame( int frame ) { if ( m_model->setCurrentAnimationFrame( frame - 1 ) ) { m_currentFrame = frame - 1; QString str = tr("Frame: "); QString numStr; numStr.sprintf( "%03d", frame ); m_countLabel->setText( str + numStr ); } else { m_countLabel->setText( tr( "Frame: n/a" ) ); } DecalManager::getInstance()->modelUpdated( m_model ); } void AnimWidget::deleteClicked() { int index = m_animName->currentIndex(); if ( (unsigned int) index < m_animCount ) { if ( QMessageBox::Ok == QMessageBox::warning( this, tr("Delete Animation?", "window title"), tr("Are you sure you want to delete this animation?"), QMessageBox::Ok, QMessageBox::Cancel ) ) { m_ignoreChange = true; Model::AnimationModeE mode = indexToMode( index ); int anim = indexToAnim( index ); m_model->deleteAnimation( mode, anim ); refreshPage(); m_ignoreChange = true; insertAnimationNames(); index--; if ( index < 0 ) { index = 0; } m_animName->setCurrentIndex( index ); nameSelected( index ); m_ignoreChange = false; m_model->operationComplete( tr( "Delete Animation", "Delete animation, operation complete" ).toUtf8() ); } } } void AnimWidget::changeFPS() { if ( !m_ignoreChange && m_animCount > 0 ) { log_debug( "changing FPS\n" ); m_model->setAnimFPS( m_mode, indexToAnim( m_animName->currentIndex() ), m_fps->text().toDouble() ); m_model->operationComplete( tr( "Set FPS", "Frames per second, operation complete" ).toUtf8() ); } } void AnimWidget::changeFrameCount() { if ( !m_ignoreChange ) { if ( m_animCount > 0 ) { m_model->setAnimFrameCount( m_mode, indexToAnim( m_animName->currentIndex() ), m_frameCount->value() ); m_model->operationComplete( tr( "Change Frame Count", "operation complete" ).toUtf8() ); m_countSlider->setMinimum( 1 ); m_countSlider->setValue( m_model->getCurrentAnimationFrame() + 1 ); setCurrentFrame( m_model->getCurrentAnimationFrame() + 1 ); m_countSlider->setMaximum( m_frameCount->value() ); m_countSlider->update(); DecalManager::getInstance()->modelAnimate( m_model ); } } } void AnimWidget::clearFrame() { Model::AnimationModeE mode = m_model->getAnimationMode(); if ( mode == Model::ANIMMODE_FRAME || mode == Model::ANIMMODE_SKELETAL ) { int anim = m_model->getCurrentAnimation(); int frame = m_model->getCurrentAnimationFrame(); m_model->clearAnimFrame( mode, anim, frame ); m_model->operationComplete( tr( "Clear frame", "Remove animation data from frame, operation complete" ).toUtf8() ); DecalManager::getInstance()->modelUpdated( m_model ); } } bool AnimWidget::copyFrame( bool selected ) { Model::AnimationModeE mode = m_model->getAnimationMode(); m_frameCopyList.clear(); m_framePointCopyList.clear(); m_keyframeCopyList.clear(); if ( mode == Model::ANIMMODE_FRAME ) { unsigned numVertices = m_model->getVertexCount(); unsigned numPoints = m_model->getPointCount(); unsigned v = 0; FrameCopy copy; copy.vertex = 0; copy.x = 0; copy.y = 0; copy.z = 0; FramePointCopy copyPoint; copyPoint.point = 0; copyPoint.x = 0; copyPoint.y = 0; copyPoint.z = 0; copyPoint.rx = 0; copyPoint.ry = 0; copyPoint.rz = 0; for ( v = 0; v < numVertices; v++ ) { if ( !selected || m_model->isVertexSelected(v) ) { if ( m_model->getFrameAnimVertexCoords( m_currentAnim, m_currentFrame, v, copy.x, copy.y, copy.z ) ) { copy.vertex = v; m_frameCopyList.push_back( copy ); } } } for ( v = 0; v < numPoints; v++ ) { if ( !selected || m_model->isPointSelected(v) ) { if ( m_model->getFrameAnimPointCoords( m_currentAnim, m_currentFrame, v, copyPoint.x, copyPoint.y, copyPoint.z ) && m_model->getFrameAnimPointRotation( m_currentAnim, m_currentFrame, v, copyPoint.rx, copyPoint.ry, copyPoint.rz ) ) { copyPoint.point = v; m_framePointCopyList.push_back( copyPoint ); } } } return ( m_frameCopyList.size() > 0 ? true : false ); } else if ( mode == Model::ANIMMODE_SKELETAL ) { unsigned numJoints = m_model->getBoneJointCount(); unsigned j = 0; KeyframeCopy copy; copy.joint = 0; copy.x = 0; copy.y = 0; copy.z = 0; copy.isRotation = false; for ( j = 0; j < numJoints; j++ ) { if ( !selected || m_model->isBoneJointSelected(j) ) { if ( m_model->getSkelAnimKeyframe( m_currentAnim, m_currentFrame, j, false, copy.x, copy.y, copy.z ) ) { copy.joint = j; copy.isRotation = false; m_keyframeCopyList.push_back( copy ); } } } for ( j = 0; j < numJoints; j++ ) { if ( !selected || m_model->isBoneJointSelected(j) ) { if ( m_model->getSkelAnimKeyframe( m_currentAnim, m_currentFrame, j, true, copy.x, copy.y, copy.z ) ) { copy.joint = j; copy.isRotation = true; m_keyframeCopyList.push_back( copy ); } } } return ( m_keyframeCopyList.size() > 0 ? true : false ); } return false; } void AnimWidget::pasteFrame() { Model::AnimationModeE mode = m_model->getAnimationMode(); if ( mode == Model::ANIMMODE_FRAME ) { if ( m_frameCopyList.empty() && m_framePointCopyList.empty() ) { msg_error( tr("No frame animation data to paste").toUtf8() ); return; } FrameCopyList::iterator it; FramePointCopyList::iterator pit; for ( it = m_frameCopyList.begin(); it != m_frameCopyList.end(); it++ ) { m_model->setFrameAnimVertexCoords( m_currentAnim, m_currentFrame, (*it).vertex, (*it).x, (*it).y, (*it).z ); } for ( pit = m_framePointCopyList.begin(); pit != m_framePointCopyList.end(); pit++ ) { m_model->setFrameAnimPointCoords( m_currentAnim, m_currentFrame, (*pit).point, (*pit).x, (*pit).y, (*pit).z ); m_model->setFrameAnimPointRotation( m_currentAnim, m_currentFrame, (*pit).point, (*pit).rx, (*pit).ry, (*pit).rz ); } m_model->operationComplete( tr( "Paste frame", "paste frame animation position, operation complete" ).toUtf8() ); m_model->setCurrentAnimationFrame( m_currentFrame ); DecalManager::getInstance()->modelUpdated( m_model ); } else if ( mode == Model::ANIMMODE_SKELETAL ) { KeyframeCopyList::iterator it; if ( m_keyframeCopyList.empty() ) { msg_error( tr("No skeletal animation data to paste").toUtf8() ); return; } for ( it = m_keyframeCopyList.begin(); it != m_keyframeCopyList.end(); it++ ) { m_model->setSkelAnimKeyframe( m_currentAnim, m_currentFrame, (*it).joint, (*it).isRotation, (*it).x, (*it).y, (*it).z ); } m_model->operationComplete( tr( "Paste keyframe", "Paste keyframe animation data complete" ).toUtf8() ); m_model->setCurrentAnimationFrame( m_currentFrame ); // Force refresh of joints DecalManager::getInstance()->modelUpdated( m_model ); } } void AnimWidget::playClicked() { if ( m_playing ) { doPause(); } else { doPlay(); } m_stop->setEnabled( true ); } void AnimWidget::stopClicked() { m_currentTime = 0; m_stop->setEnabled( false ); m_play->setEnabled(true); m_frameCount->setEnabled(true); m_countSlider->setEnabled(true); m_playing = false; m_animTimer->stop(); m_model->setCurrentAnimationFrame( m_countSlider->value() - 1 ); DecalManager::getInstance()->modelUpdated( m_model ); } void AnimWidget::loopToggled( bool o ) { if ( !m_ignoreChange && m_animCount > 0 ) { log_debug( "toggling loop\n" ); m_model->setAnimationLooping( m_mode, indexToAnim( m_animName->currentIndex() ), o ); m_model->operationComplete( tr( "Set Looping", "Looping, operation complete" ).toUtf8() ); m_model->setCurrentAnimationFrame( m_countSlider->value() - 1 ); DecalManager::getInstance()->modelUpdated( m_model ); } } void AnimWidget::doPlay() { m_playing = true; if ( m_animCount == 0 ) { return; } m_play->setEnabled(false); m_frameCount->setEnabled(false); m_countSlider->setEnabled(false); m_timeInterval = double (1.0 / m_model->getAnimFPS( m_mode, indexToAnim( m_animName->currentIndex() ) )); const double shortInterval = 1.0 / 20.0; if ( m_timeInterval > shortInterval ) m_timeInterval = shortInterval; PORT_gettimeofday( &m_startTime ); m_animTimer->start( (int) (m_timeInterval * 1000) ); log_debug( "starting %s animation, update every %.03f seconds\n", (m_mode == Model::ANIMMODE_SKELETAL ? "skeletal" : "frame" ), m_timeInterval ); } void AnimWidget::doPause() { m_playing = false; m_play->setEnabled(true); m_animTimer->stop(); } void AnimWidget::timeElapsed() { PORT_timeval tv; PORT_gettimeofday( &tv ); unsigned t = (tv.tv_sec - m_startTime.tv_sec) * 1000 + (tv.tv_msec - m_startTime.tv_msec); m_currentTime = ((double) t) / 1000.0; if ( m_model->setCurrentAnimationTime( m_currentTime ) ) { //log_debug( "animation time: %f (%d)\n", m_currentTime, t ); } else { stopClicked(); //log_debug( "animation time: %f (complete)\n", m_currentTime ); } DecalManager::getInstance()->modelAnimate( m_model ); } void AnimWidget::undoRequest() { log_debug( "anim undo request\n" ); m_model->undo(); undoGuts(); } void AnimWidget::redoRequest() { log_debug( "anim redo request\n" ); m_model->redo(); undoGuts(); } void AnimWidget::undoGuts() { if ( !m_model->getAnimationMode() ) { stopAnimationMode(); return; } m_undoing = true; Model::AnimationModeE mode = m_model->inSkeletalMode() ? Model::ANIMMODE_SKELETAL : Model::ANIMMODE_FRAME; unsigned anim = m_model->getCurrentAnimation(); unsigned frame = m_model->getCurrentAnimationFrame(); insertAnimationNames(); m_animName->setCurrentIndex( animToIndex( mode, anim ) ); m_model->setCurrentAnimation( mode, anim ); m_model->setCurrentAnimationFrame( frame ); m_currentAnim = anim; m_currentFrame = frame; m_mode = mode; m_undoing = false; refreshPage(); DecalManager::getInstance()->modelUpdated( m_model ); } void AnimWidget::insertAnimationNames() { m_animName->clear(); unsigned int t; m_skelAnimCount = m_model->getAnimCount( Model::ANIMMODE_SKELETAL ); for ( t = 0; t < m_skelAnimCount; t++ ) { m_animName->insertItem( t, QString::fromUtf8( m_model->getAnimName( Model::ANIMMODE_SKELETAL, t )), t ); } m_frameAnimCount = m_model->getAnimCount( Model::ANIMMODE_FRAME ); for ( t = 0; t < m_frameAnimCount; t++ ) { m_animName->insertItem( m_skelAnimCount + t, QString( m_model->getAnimName( Model::ANIMMODE_FRAME, t )), t + m_skelAnimCount ); } m_animCount = m_skelAnimCount + m_frameAnimCount; m_animName->insertItem( m_animCount, tr( "" ), m_animCount ); } void AnimWidget::refreshPage() { log_debug( "refresh anim window page\n" ); if ( !m_undoing ) { if( m_animCount > 0 ) { int index = m_animName->currentIndex(); Model::AnimationModeE mode = indexToMode( index ); index = indexToAnim( index ); m_deleteButton->setEnabled( true ); if ( m_playing ) { m_frameCount->setEnabled( false ); m_countSlider->setEnabled( false ); } else { m_frameCount->setEnabled( true ); m_countSlider->setEnabled( true ); } m_fps->setEnabled( true ); m_animName->setEnabled( true ); m_play->setEnabled( true ); m_loop->setEnabled( true ); unsigned count = m_model->getAnimFrameCount( mode, index ); m_ignoreChange = true; // Qt alerts us even if we're responsible m_frameCount->setValue( count ); m_fps->setText( QString::number(m_model->getAnimFPS( mode, index ) ) ); m_loop->setChecked( m_model->getAnimationLooping( mode, index ) ); m_ignoreChange = false; m_countSlider->setMinimum( 1 ); m_countSlider->setMaximum( count ); m_countSlider->setValue( m_currentFrame + 1 ); m_countSlider->setTickInterval( getSliderTickInterval( count ) ); m_countSlider->update(); setCurrentFrame( m_currentFrame + 1 ); emit animValid(); } else { m_deleteButton->setEnabled( false ); m_frameCount->setEnabled( false ); m_fps->setEnabled( false ); m_countSlider->setEnabled( false ); m_play->setEnabled( false ); m_stop->setEnabled( false ); m_loop->setEnabled( false ); m_fps->setText( QString("0") ); m_loop->setChecked( false ); m_ignoreChange = true; // Qt alerts us even if we're responsible m_frameCount->setValue( 0 ); m_ignoreChange = false; m_countSlider->setMinimum( 0 ); m_countSlider->setMaximum( 0 ); m_countSlider->setValue( 0 ); setCurrentFrame( 0 ); emit animInvalid(); } } else { if ( m_animCount > 0) { m_animName->setEnabled( true ); if ( m_playing ) { m_frameCount->setEnabled( false ); m_countSlider->setEnabled( false ); } else { m_frameCount->setEnabled( true ); m_countSlider->setEnabled( true ); } m_fps->setEnabled( true ); m_play->setEnabled( true ); m_stop->setEnabled( true ); m_loop->setEnabled( true ); } else { //m_animName->setEnabled( false ); m_frameCount->setEnabled( false ); m_fps->setEnabled( false ); m_countSlider->setEnabled( false ); m_play->setEnabled( false ); m_stop->setEnabled( false ); m_loop->setEnabled( false ); m_fps->setText( QString("0") ); m_loop->setChecked( false ); m_ignoreChange = true; // Qt alerts us even if we're responsible m_frameCount->setValue( 0 ); m_ignoreChange = false; m_countSlider->setMinimum( 0 ); m_countSlider->setMaximum( 0 ); m_countSlider->setValue( 0 ); } } } void AnimWidget::stopAnimationMode() { if ( m_needShutdown ) { if ( m_model->getAnimationMode() ) { m_model->setNoAnimation(); m_model->operationComplete( tr( "End animation mode", "operation complete" ).toUtf8() ); DecalManager::getInstance()->modelUpdated( m_model ); } emit animWindowClosed(); } m_needShutdown = false; } bool AnimWidget::indexIsSkel( int index ) { if ( index >= (int) m_skelAnimCount ) { return false; } else { return true; } } Model::AnimationModeE AnimWidget::indexToMode( int index ) { if ( index >= (int) m_skelAnimCount ) { return Model::ANIMMODE_FRAME; } else { return Model::ANIMMODE_SKELETAL; } } int AnimWidget::indexToAnim( int index ) { if ( index >= (int) m_skelAnimCount ) { return index -= m_skelAnimCount; } else { return index; } } int AnimWidget::animToIndex( Model::AnimationModeE mode, int anim ) { if ( mode == Model::ANIMMODE_FRAME ) { return anim + m_skelAnimCount; } else { return anim; } } mm3d-master/src/implui/animwidget.h000066400000000000000000000066161324021725400176070ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ANIMWIDGET_H #define __ANIMWIDGET_H #include "animwidget.base.h" #include "mm3dport.h" #include "model.h" #include class QTimer; class AnimWidget : public QWidget, public Ui::AnimWidgetBase { Q_OBJECT public: AnimWidget( Model * model, bool isUndo, QWidget * parent = NULL ); virtual ~AnimWidget(); void initialize( Model * model, bool isUndo ); void stopAnimationMode(); void doPlay(); void doPause(); signals: void animWindowClosed(); void animInvalid(); void animValid(); public slots: void nameSelected(int); void deleteClicked(); void setCurrentFrame(int); void changeFPS(); void changeFrameCount(); void timeElapsed(); void playClicked(); void stopClicked(); void loopToggled(bool); bool copyFrame( bool selected ); void pasteFrame(); void clearFrame(); void undoRequest(); void redoRequest(); void refreshPage(); protected: bool indexIsSkel( int index ); Model::AnimationModeE indexToMode( int index ); int indexToAnim( int index ); int animToIndex( Model::AnimationModeE mode, int anim ); void undoGuts(); void insertAnimationNames(); Model * m_model; bool m_playing; double m_timeInterval; double m_currentTime; unsigned m_skelAnimCount; unsigned m_frameAnimCount; unsigned m_animCount; unsigned m_currentAnim; unsigned m_currentFrame; Model::AnimationModeE m_mode; bool m_undoing; bool m_ignoreChange; bool m_needShutdown; PORT_timeval m_startTime; typedef struct _KeyframeCopy_t { unsigned joint; double x; double y; double z; bool isRotation; } KeyframeCopy; typedef struct _FrameCopy_t { unsigned vertex; double x; double y; double z; } FrameCopy; typedef struct _FramePointCopy_t { unsigned point; double x; double y; double z; double rx; double ry; double rz; } FramePointCopy; typedef std::list KeyframeCopyList; typedef std::list FrameCopyList; typedef std::list FramePointCopyList; KeyframeCopyList m_keyframeCopyList; FrameCopyList m_frameCopyList; FramePointCopyList m_framePointCopyList; QTimer * m_animTimer; }; #endif // __ANIMWIDGET_H mm3d-master/src/implui/animwin.cc000066400000000000000000000025011324021725400172440ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "animwin.h" #include "log.h" #include AnimWindow::AnimWindow( Model * model, bool isUndo, QWidget * parent ) : QDockWidget( tr("Animations"), parent ), m_animWidget( new AnimWidget( model, isUndo, this ) ) { setWidget( m_animWidget ); } AnimWindow::~AnimWindow() { log_debug( "Destroying AnimWindow()\n" ); } void AnimWindow::close() { QDockWidget::hide(); } void AnimWindow::closeEvent( QCloseEvent * e ) { emit animWindowClosed(); } mm3d-master/src/implui/animwin.h000066400000000000000000000026131324021725400171120ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef ANIMWIN_H_INC__ #define ANIMWIN_H_INC__ #include #include "animwidget.h" class Model; class AnimWindow : public QDockWidget { Q_OBJECT public: AnimWindow( Model * model, bool isUndo, QWidget * parent = NULL ); virtual ~AnimWindow(); AnimWidget * getAnimWidget() { return m_animWidget; } signals: void animWindowClosed(); public slots: void close(); protected: void closeEvent( QCloseEvent * e ); private: AnimWidget * m_animWidget; }; #endif // ANIMWIN_H_INC__ mm3d-master/src/implui/autoassignjointwin.cc000066400000000000000000000035561324021725400215540ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "autoassignjointwin.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "helpwin.h" #include #include #include using std::list; using std::map; AutoAssignJointWin::AutoAssignJointWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setModal( true ); setupUi( this ); if ( m_model->getSelectedBoneJointCount() == 0 ) { m_selected->setChecked( false ); m_selected->setEnabled( false ); } QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } AutoAssignJointWin::~AutoAssignJointWin() { } void AutoAssignJointWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_autoassignjointwin.html", true ); win->show(); } int AutoAssignJointWin::getSensitivity() { return m_sensitivity->value(); } bool AutoAssignJointWin::getSelected() { return m_selected->isChecked(); } mm3d-master/src/implui/autoassignjointwin.h000066400000000000000000000025461324021725400214140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __AUTOASSIGNJOINTWIN_H #define __AUTOASSIGNJOINTWIN_H #include "autoassignjointwin.base.h" #include class Model; class AutoAssignJointWin : public QDialog, public Ui::AutoAssignJointWinBase { Q_OBJECT public: AutoAssignJointWin( Model *, QWidget * parent = NULL ); virtual ~AutoAssignJointWin(); int getSensitivity(); bool getSelected(); public slots: void helpNowEvent(); protected: Model * m_model; }; #endif // __AUTOASSIGNJOINTWIN_H mm3d-master/src/implui/backgroundselect.cc000066400000000000000000000075251324021725400211340ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "backgroundselect.h" #include "model.h" #include "log.h" #include "msg.h" #include "decalmgr.h" #include "textureframe.h" #include "3dmprefs.h" #include "texmgr.h" #include "texture.h" #include "model.h" #include "errorobj.h" #include #include #include #include #include using std::list; using std::map; BackgroundSelect::BackgroundSelect( Model * model, unsigned index, QWidget * parent ) : QWidget( parent ), m_model( model ), m_index( index ) { setupUi( this ); std::string filename = m_model->getBackgroundImage( index ); setFilename( filename.c_str() ); m_textureFrame->updateSize(); } BackgroundSelect::~BackgroundSelect() { } void BackgroundSelect::noneEvent() { m_model->setBackgroundImage( m_index, "" ); m_textureFrame->setTexture( -1, NULL ); m_textureFrame->updateSize(); } void BackgroundSelect::selectFileEvent() { list formats = TextureManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += " "; } } formatsStr += ")"; QString dir = QString::fromUtf8( g_prefs( "ui_background_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = "."; } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; All Files (*)" ) ); d.setWindowTitle( tr("Open background image") ); d.selectNameFilter( formatsStr ); int execval = d.exec(); QStringList files = d.selectedFiles(); if ( QDialog::Accepted == execval && !files.empty() ) { std::string file = (const char *) files[0].toUtf8(); QString path = d.directory().absolutePath(); g_prefs( "ui_background_dir" ) = (const char *) path.toUtf8(); Texture * tex = TextureManager::getInstance()->getTexture( file.c_str() ); if ( tex ) { m_model->setBackgroundImage( m_index, file.c_str() ); m_textureFrame->setTexture( -1, tex ); m_textureFrame->updateSize(); // Do NOT delete tex, TextureManager does that } else { QString err = tr(file.c_str()) + "\n"; Texture::ErrorE e = TextureManager::getInstance()->getLastError(); if ( e != Texture::ERROR_NONE ) { err += textureErrStr( e ); } else { err += tr("Could not open file"); } msg_error( (const char *) err.toUtf8() ); } } } void BackgroundSelect::setFilename( const char * filename ) { Texture * tex = TextureManager::getInstance()->getTexture( filename ); if ( tex ) { m_model->setBackgroundImage( m_index, filename ); m_textureFrame->setTexture( -1, tex ); m_textureFrame->updateSize(); // Do NOT delete tex, TextureManager does that } } mm3d-master/src/implui/backgroundselect.h000066400000000000000000000026341324021725400207720ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BACKGROUNDSELECT_H #define __BACKGROUNDSELECT_H #include "backgroundselect.base.h" #include class Model; class BackgroundSelect : public QWidget, public Ui::BackgroundSelectBase { Q_OBJECT public: BackgroundSelect( Model * mode, unsigned index, QWidget * parent = NULL ); virtual ~BackgroundSelect(); public slots: void setFilename( const char * filename ); void noneEvent(); void selectFileEvent(); protected: Model * m_model; unsigned m_index; }; #endif // __BACKGROUNDSELECT_H mm3d-master/src/implui/backgroundwin.cc000066400000000000000000000045451324021725400204510ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "backgroundwin.h" #include "backgroundselect.h" #include "model.h" #include "log.h" #include "decalmgr.h" #include "textureframe.h" #include "helpwin.h" #include #include #include #include #include #include using std::list; using std::map; BackgroundWin::BackgroundWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); for ( unsigned t = 0; t < 6; t++ ) { QWidget * p = m_tabs->widget( t ); QHBoxLayout * l = new QHBoxLayout( p ); m_bgSelect[t] = new BackgroundSelect( m_model, t, p ); l->addWidget( m_bgSelect[t] ); } QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } BackgroundWin::~BackgroundWin() { } void BackgroundWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_backgroundwin.html", true ); win->show(); } void BackgroundWin::selectedPageEvent( const QString & str ) { QWidget * widget = m_tabs->currentWidget(); widget->repaint(); } void BackgroundWin::accept() { m_model->operationComplete( tr( "Background Image", "operation complete" ).toUtf8() ); QDialog::accept(); } void BackgroundWin::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/backgroundwin.h000066400000000000000000000026461324021725400203130ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BACKGROUNDWIN_H #define __BACKGROUNDWIN_H #include "backgroundwin.base.h" #include class Model; class BackgroundSelect; class BackgroundWin : public QDialog, public Ui::BackgroundWinBase { Q_OBJECT public: BackgroundWin( Model *, QWidget * parent = NULL ); virtual ~BackgroundWin(); public slots: void selectedPageEvent( const QString & str ); void accept(); void reject(); void helpNowEvent(); protected: Model * m_model; BackgroundSelect * m_bgSelect[6]; }; #endif // __BACKGROUNDWIN_H mm3d-master/src/implui/boolpanel.cc000066400000000000000000000036771324021725400175740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "boolpanel.h" #include "viewpanel.h" #include "boolwin.h" #include "log.h" #include #include BoolPanel::BoolPanel( Model * model, QWidget * parent, ViewPanel * panel ) : QDockWidget( tr("Boolean Operation"), parent ), m_panel( panel ), m_boolWidget( new BoolWin( model, panel, this ) ) { setWidget( m_boolWidget ); } BoolPanel::~BoolPanel() { } void BoolPanel::setModel( Model * model ) { m_boolWidget->setModel( model ); } void BoolPanel::modelChanged( int changeBits ) { if ( this->isVisible() ) { } } void BoolPanel::show() { QDockWidget::show(); // this is causing a segfault on dock/undock because the widgets // are being destroyed and re-created. The solution is to call setModel // explicitly whenever the window is shown (this only happens in viewwin.cc) //setModel( m_model ) } void BoolPanel::close() { hide(); // Do hide instead } void BoolPanel::hide() { log_debug( "BoolPanel::hide()\n" ); QDockWidget::hide(); } void BoolPanel::contextMenuEvent( QContextMenuEvent * e ) { e->ignore(); } mm3d-master/src/implui/boolpanel.h000066400000000000000000000031411324021725400174200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BOOLPANEL_H #define __BOOLPANEL_H #include "contextwidget.h" #include "model.h" #include class QContextMenuEvent; class ViewPanel; class BoolWin; class BoolPanel : public QDockWidget, public Model::Observer { Q_OBJECT public: BoolPanel( Model * model, QWidget * parent, ViewPanel * panel ); virtual ~BoolPanel(); // QDockWindow methods public slots: void show(); void close(); void hide(); void setModel( Model * m ); // Model::Observer methods void modelChanged( int changeBits ); protected: void contextMenuEvent( QContextMenuEvent * e ); Model * m_model; ViewPanel * m_panel; BoolWin * m_boolWidget; }; #endif // __BOOLPANEL_H mm3d-master/src/implui/boolwin.cc000066400000000000000000000114101324021725400172520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "boolwin.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "decalmgr.h" #include "helpwin.h" #include "viewpanel.h" #include "modelstatus.h" #include #include #include #include #include using std::list; BoolWin::BoolWin( Model * model, ViewPanel * panel, QWidget * parent ) : QWidget( parent ), m_model( model ), m_panel( panel ), m_operation( Model::BO_Union ) { setupUi( this ); m_unionButton->setChecked( true ); updateOperationButton(); clearObject(); } BoolWin::~BoolWin() { } void BoolWin::setModel( Model * m ) { m_model = m; clearObject(); } void BoolWin::operationChangedEvent( bool o) { if ( o ) { if ( m_fuseButton->isChecked() ) { m_operation = Model::BO_Union; } else if ( m_unionButton->isChecked() ) { m_operation = Model::BO_UnionRemove; } else if ( m_subtractButton->isChecked() ) { m_operation = Model::BO_Subtraction; } else if ( m_intersectButton->isChecked() ) { m_operation = Model::BO_Intersection; } updateOperationButton(); } } void BoolWin::doOperationEvent() { std::list al; std::list bl; unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { bl.push_back( t ); } else if ( m_model->isTriangleMarked( t ) ) { al.push_back( t ); } } if ( !al.empty() && !bl.empty() ) { m_model->booleanOperation( m_operation, al, bl ); QString opStr; switch ( m_operation ) { case Model::BO_UnionRemove: opStr = tr( "Union", "boolean operation" ); break; case Model::BO_Subtraction: opStr = tr( "Subtraction", "boolean operation" ); break; case Model::BO_Intersection: opStr = tr( "Intersection", "boolean operation" ); break; case Model::BO_Union: default: opStr = tr( "Union", "boolean operation" ); break; } m_model->operationComplete( opStr.toUtf8() ); clearObject(); m_panel->modelUpdatedEvent(); } else { if ( bl.empty() ) { model_status( m_model, StatusError, STATUSTIME_LONG, tr("You must have at least once face selected").toUtf8() ); } else { model_status( m_model, StatusError, STATUSTIME_LONG, tr("Object A triangles are still selected").toUtf8() ); } } } void BoolWin::setObjectEvent() { std::list tris; m_model->getSelectedTriangles( tris ); if ( !tris.empty() ) { m_opButton->setEnabled( true ); QString labelStr; labelStr.sprintf( "Object: %d Faces", (int) tris.size() ); m_setLabel->setText( labelStr ); m_model->clearMarkedTriangles(); std::list::iterator it; for ( it = tris.begin(); it != tris.end(); it++ ) { m_model->setTriangleMarked( *it, true ); } } else { m_opButton->setEnabled( false ); } } void BoolWin::updateOperationButton() { switch ( m_operation ) { case Model::BO_UnionRemove: m_opButton->setText( tr( "Union With Selected", "boolean operation" ) ); break; case Model::BO_Subtraction: m_opButton->setText( tr( "Subtract Selected", "boolean operation" ) ); break; case Model::BO_Intersection: m_opButton->setText( tr( "Intersect With Selected", "boolean operation" ) ); break; case Model::BO_Union: default: m_opButton->setText( tr( "Fuse Selected", "boolean operation" ) ); break; } } void BoolWin::clearObject() { m_setLabel->setText( tr( "Select faces to set", "Select faces to set as 'A' Object in boolean operation" ) ); m_opButton->setEnabled( false ); } mm3d-master/src/implui/boolwin.h000066400000000000000000000027541324021725400171270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BOOLWIN_H #define __BOOLWIN_H #include "boolwin.base.h" #include "model.h" #include class ViewPanel; class BoolWin : public QWidget, public Ui::BoolWinBase { Q_OBJECT public: BoolWin( Model *, ViewPanel * panel, QWidget * parent = NULL ); virtual ~BoolWin(); void setModel( Model * ); public slots: void operationChangedEvent( bool ); void doOperationEvent(); void setObjectEvent(); protected: void updateOperationButton(); void clearObject(); Model * m_model; ViewPanel * m_panel; Model::BooleanOpE m_operation; }; #endif // __BOOLWIN_H mm3d-master/src/implui/cal3dprompt.cc000066400000000000000000000051301324021725400200330ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cal3dprompt.h" #include "cal3dfilter.h" #include "model.h" #include "helpwin.h" #include #include Cal3dPrompt::Cal3dPrompt() : QDialog( NULL ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } Cal3dPrompt::~Cal3dPrompt() { } void Cal3dPrompt::setOptions( Cal3dFilter::Cal3dOptions * opts ) { if ( opts->m_singleMeshFile ) m_singleMeshFile->setChecked( true ); else m_separateMeshFiles->setChecked( true ); if ( opts->m_xmlMatFile ) m_xmlMatFile->setChecked( true ); else m_binaryMatFile->setChecked( true ); } void Cal3dPrompt::getOptions( Cal3dFilter::Cal3dOptions * opts ) { opts->m_singleMeshFile = m_singleMeshFile->isChecked(); opts->m_xmlMatFile = m_xmlMatFile->isChecked(); } void Cal3dPrompt::helpNowEvent() { HelpWin * win = new HelpWin( "olh_cal3dprompt.html", true ); win->show(); } // This function takes a ModelFilter::Options argument, downcasts it // to an Cal3dOptions cal3dect, and uses it to prompt the user for // options for the Cal3d file filter. // // This function is registered with the Cal3dFilter class when the // filter is created in stdfilters.cc. bool cal3dprompt_show( Model * model, ModelFilter::Options * o ) { bool rval = false; Cal3dPrompt p; Cal3dFilter::Cal3dOptions * opts = dynamic_cast< Cal3dFilter::Cal3dOptions * >( o ); if ( opts ) { opts->setOptionsFromModel( model ); p.setOptions( opts ); if ( p.exec() ) { rval = true; p.getOptions( opts ); } } else { rval = true; } return rval; } mm3d-master/src/implui/cal3dprompt.h000066400000000000000000000026431324021725400177030ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CAL3DPROMPT_H #define __CAL3DPROMPT_H #include "cal3dprompt.base.h" #include "modelfilter.h" #include "cal3dfilter.h" #include class Model; class Cal3dPrompt : public QDialog, public Ui::Cal3dPromptBase { Q_OBJECT public: Cal3dPrompt(); virtual ~Cal3dPrompt(); void setOptions( Cal3dFilter::Cal3dOptions * o ); void getOptions( Cal3dFilter::Cal3dOptions * o ); public slots: void helpNowEvent(); protected: }; bool cal3dprompt_show( Model * model, ModelFilter::Options * o ); #endif // __CAL3DPROMPT_H mm3d-master/src/implui/contextgroup.cc000066400000000000000000000174501324021725400203540ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextgroup.h" #include "model.h" #include "contextpanelobserver.h" #include "groupwin.h" #include "texwin.h" #include "projectionwin.h" #include #include #include #include #include #include ContextGroup::ContextGroup( QWidget * parent, ContextPanelObserver * ob ) : QWidget( parent ), m_model( NULL ), m_observer( ob ), m_change( false ), m_update( false ) { setupUi( this ); } ContextGroup::~ContextGroup() { } void ContextGroup::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextGroup::modelChanged( int changeBits ) { // Only change if it's a group change or a selection change if ( (changeBits & Model::AddOther) || (changeBits & Model::SelectionChange ) ) { if ( !m_update ) { m_change = true; // Update group fields m_groupValue->clear(); m_groupValue->insertItem( 0, tr( "" ) ); m_materialValue->clear(); m_materialValue->insertItem( 0, tr( "" ) ); m_projectionValue->clear(); m_projectionValue->insertItem( 0, tr( "" ) ); unsigned int gcount = m_model->getGroupCount(); for ( unsigned int g = 0; g < gcount; g++ ) { m_groupValue->insertItem( g + 1, QString::fromUtf8( m_model->getGroupName( g ) ) ); } m_groupValue->insertItem( m_groupValue->count(), tr( "" ) ); unsigned int mcount = m_model->getTextureCount(); for ( unsigned int m = 0; m < mcount; m++ ) { m_materialValue->insertItem( m + 1, QString::fromUtf8( m_model->getTextureName( m ) ) ); } unsigned int pcount = m_model->getProjectionCount(); for ( unsigned int p = 0; p < pcount; p++ ) { m_projectionValue->insertItem( p + 1, QString::fromUtf8( m_model->getProjectionName( p ) ) ); } int group = -1; int proj = -1; unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; (group < 0 || proj < 0) && t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { if ( group < 0 ) { group = m_model->getTriangleGroup( t ); } if ( proj < 0 ) { proj = m_model->getTriangleProjection( t ); } } } if ( group >= 0 ) { m_materialValue->setEnabled( true ); m_materialProperties->setEnabled( true ); m_groupValue->setCurrentIndex( group + 1 ); int texId = m_model->getGroupTextureId( group ); if ( texId >= 0 ) { m_materialValue->setCurrentIndex( texId + 1 ); } } else { m_materialValue->setEnabled( false ); m_materialProperties->setEnabled( false ); } if ( proj >= 0 ) { m_projectionProperties->setEnabled( true ); m_projectionValue->setCurrentIndex( proj + 1 ); } else { m_projectionProperties->setEnabled( false ); } m_change = false; } } m_lastGroup = m_groupValue->currentIndex(); } void ContextGroup::groupChanged() { if ( !m_change ) { m_update = true; int g = m_groupValue->currentIndex() - 1; if ( g >= 0 ) { m_materialValue->setEnabled( true ); m_materialProperties->setEnabled( true ); bool addSelected = true; if ( g >= m_model->getGroupCount() ) { // TODO pick unique name? QString groupName = QInputDialog::getText( this, tr("New Group", "Name of new group, window title" ), tr("Enter new group name:"), QLineEdit::Normal, QString::null, &addSelected ); if ( groupName.length() == 0 ) { addSelected = false; } if ( addSelected ) { m_model->addGroup( groupName.toUtf8() ); m_groupValue->setItemText( g + 1, groupName ); m_groupValue->insertItem( m_groupValue->count(), tr( "" ) ); } else { m_groupValue->setCurrentIndex( m_lastGroup ); } } if ( addSelected ) { m_model->addSelectedToGroup( g ); m_model->operationComplete( tr( "Set Group", "operation complete" ).toUtf8() ); } int texId = m_model->getGroupTextureId( g ); if ( texId >= 0 ) { m_materialValue->setCurrentIndex( texId + 1 ); } else { m_materialValue->setCurrentIndex( 0 ); } } else { m_materialValue->setEnabled( false ); m_materialProperties->setEnabled( false ); unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { g = m_model->getTriangleGroup( t ); if ( g >= 0 ) { m_model->removeTriangleFromGroup( g, t ); } } } m_model->operationComplete( tr( "Unset Group", "operation complete" ).toUtf8() ); } emit panelChange(); m_update = false; } } void ContextGroup::materialChanged() { if ( !m_change ) { m_update = true; int g = m_groupValue->currentIndex() - 1; int m = m_materialValue->currentIndex() - 1; if ( g >= 0 ) { m_model->setGroupTextureId( g, m ); m_model->operationComplete( tr( "Set Material", "operation complete" ).toUtf8() ); } emit panelChange(); m_update = false; } } void ContextGroup::projectionChanged() { if ( !m_change ) { m_update = true; int proj = m_projectionValue->currentIndex() - 1; unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { m_model->setTriangleProjection( t, proj ); } } if ( proj >= 0 ) { m_model->applyProjection( proj ); m_projectionProperties->setEnabled( true ); } else { m_projectionProperties->setEnabled( false ); } m_model->operationComplete( tr( "Set Projection", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } void ContextGroup::groupPropertiesClicked() { GroupWindow * win = new GroupWindow( m_model ); win->show(); } void ContextGroup::materialPropertiesClicked() { TextureWindow * win = new TextureWindow( m_model ); win->show(); } void ContextGroup::projectionPropertiesClicked() { m_observer->showProjectionEvent(); } mm3d-master/src/implui/contextgroup.h000066400000000000000000000035251324021725400202140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTGROUP_H #define __CONTEXTGROUP_H class ContextPanelObserver; #include "contextgroup.base.h" #include "contextwidget.h" #include class Model; class ContextGroup : public QWidget, public Ui::ContextGroupBase, public ContextWidget { Q_OBJECT public: ContextGroup( QWidget * parent, ContextPanelObserver * ob ); virtual ~ContextGroup(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Group slots void groupChanged(); void groupPropertiesClicked(); void projectionChanged(); void projectionPropertiesClicked(); void materialChanged(); void materialPropertiesClicked(); protected: Model * m_model; ContextPanelObserver * m_observer; bool m_change; bool m_update; int m_lastGroup; }; #endif // __CONTEXTGROUP_H mm3d-master/src/implui/contextinfluences.cc000066400000000000000000000432051324021725400213500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextinfluences.h" #include "groupwin.h" #include "texwin.h" #include "config.h" #include "log.h" #include #include #include #include #include ContextInfluences::JointCount::JointCount() : inList( false ), count( 0 ), typeIndex( Model::IT_Auto + 1 ), weight( 0 ) { for ( int t = 0; t < Model::IT_MAX; t++ ) { typeCount[t] = 0; } } ContextInfluences::ContextInfluences( QWidget * parent ) : QWidget( parent ), m_change( false ), m_update( false ) { setupUi( this ); } ContextInfluences::~ContextInfluences() { } void ContextInfluences::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextInfluences::modelChanged( int changeBits ) { // Only change if it's a group change or a selection change if ( (changeBits & Model::AddOther) || (changeBits & Model::SelectionChange ) ) { if ( !m_update ) { m_change = true; m_joint1->clear(); m_joint2->clear(); m_joint3->clear(); m_joint4->clear(); m_joint1->insertItem( 0, tr("") ); m_joint2->insertItem( 0, tr("") ); m_joint3->insertItem( 0, tr("") ); m_joint4->insertItem( 0, tr("") ); int bcount = m_model->getBoneJointCount(); for ( int b = 0; b < bcount; b++ ) { QString name = QString::fromUtf8( m_model->getBoneJointName( b ) ); m_joint1->insertItem( b+1, name ); m_joint2->insertItem( b+1, name ); m_joint3->insertItem( b+1, name ); m_joint4->insertItem( b+1, name ); } m_joint1->setCurrentIndex( 0 ); m_joint2->setCurrentIndex( 0 ); m_joint3->setCurrentIndex( 0 ); m_joint4->setCurrentIndex( 0 ); m_joints[0] = -1; m_joints[1] = -1; m_joints[2] = -1; m_joints[3] = -1; m_weight1->setEnabled( false ); m_weight2->setEnabled( false ); m_weight3->setEnabled( false ); m_weight4->setEnabled( false ); if ( m_model->getAnimationMode() != Model::ANIMMODE_NONE ) { m_joint1->setEnabled( false ); m_joint2->setEnabled( false ); m_joint3->setEnabled( false ); m_joint4->setEnabled( false ); } // Update influence fields m_jclist.clear(); m_jclist.resize( bcount ); list< Model::Position > plist; list< Model::Position >::iterator pit; Model::InfluenceList ilist; Model::InfluenceList::iterator iit; m_model->getSelectedPositions( plist ); // for now just do a sum on which bone joints are used the most // TODO: may want to weight by influence later for ( pit = plist.begin(); pit != plist.end(); pit++ ) { ilist.clear(); m_model->getPositionInfluences( (*pit), ilist ); for ( iit = ilist.begin(); iit != ilist.end(); iit++ ) { int bone = (*iit).m_boneId; m_jclist[ bone ].count += 1; m_jclist[ bone ].weight += (int) ((*iit).m_weight * 100.0); m_jclist[ bone ].typeCount[ (*iit).m_type ] += 1; } } for ( int joint = 0; joint < bcount; joint++ ) { int typeIndex = -1; for ( int t = 0; typeIndex != 0 && t < Model::IT_MAX; t++ ) { if ( m_jclist[ joint ].typeCount[ t ] > 0 ) { // If type index is unset, set it to the combo box // index for our type (off by one). If type index // is already set, it's mixed (index 0) typeIndex = ( typeIndex < 0 ) ? t + 1 : 0; } } if ( typeIndex >= 0 ) { m_jclist[ joint ].typeIndex = typeIndex; m_jclist[ joint ].weight /= m_jclist[ joint ].count; } else { m_jclist[ joint ].weight = 100; } } for ( int index = 0; index < Model::MAX_INFLUENCES; index++ ) { int maxVal = 0; int joint = -1; for ( int b = 0; b < bcount; b++ ) { if ( !m_jclist[ b ].inList && m_jclist[ b ].count > maxVal ) { maxVal = m_jclist[b].count; joint = b; } } if ( maxVal > 0 ) { QComboBox * jointBox = m_joint1; switch ( index ) { case 0: jointBox = m_joint1; break; case 1: jointBox = m_joint2; break; case 2: jointBox = m_joint3; break; case 3: jointBox = m_joint4; break; default: break; } jointBox->setCurrentIndex( joint + 1 ); updateWeightField( index, true, m_jclist[ joint ].typeIndex, m_jclist[ joint ].weight ); //updateRemainders(); m_joints[index] = joint; log_debug( "joint index %d is joint ID %d\n", index, joint ); m_jclist[ joint ].inList = true; } else { // No more influenes, we're done index = Model::MAX_INFLUENCES; } } m_change = false; } } } void ContextInfluences::jointChanged( int index, int oldJoint, int newJoint ) { if ( !m_change ) { m_update = true; if ( newJoint >= 0 ) { for ( int i = 0; i < Model::MAX_INFLUENCES; i++ ) { if ( m_joints[i] == newJoint ) { // trying to assign new joint when we already have that joint // in one of the edit boxes. Change the selection back. This // will cause some nasty bugs and probably confuse the user. // Change the selection back. m_change = true; switch ( index ) { case 0: m_joint1->setCurrentIndex( oldJoint + 1 ); break; case 1: m_joint2->setCurrentIndex( oldJoint + 1 ); break; case 2: m_joint3->setCurrentIndex( oldJoint + 1 ); break; case 3: m_joint4->setCurrentIndex( oldJoint + 1 ); break; default: break; } m_change = false; m_update = false; return; } } } std::list l; m_model->getSelectedPositions( l ); std::list::iterator it; if ( oldJoint >= 0 ) { m_jclist[ oldJoint ].count = 0; for ( it = l.begin(); it != l.end(); it++ ) { m_model->removePositionInfluence( *it, oldJoint ); } } int weight = 0; if ( newJoint >= 0 ) { m_jclist[ newJoint ].count = l.size(); for ( it = l.begin(); it != l.end(); it++ ) { double w = m_model->calculatePositionInfluenceWeight( *it, newJoint ); log_debug( "influence = %f\n", w ); m_model->addPositionInfluence( *it, newJoint, Model::IT_Auto, w ); weight += (int) (w * 100.0); } if ( !l.empty() ) { m_jclist[ newJoint ].weight = weight / l.size(); } m_jclist[ newJoint ].typeIndex = Model::IT_Auto + 1; } m_joints[ index ] = newJoint; bool enabled = false; if ( newJoint >= 0 ) { enabled = true; m_change = true; updateWeightField( index, true, m_jclist[ newJoint ].typeIndex, m_jclist[ newJoint ].weight ); updateRemainders(); m_change = false; } else { updateWeightField( index, false, 0, 0 ); updateRemainders(); } m_model->operationComplete( tr( "Change Joint Assignment", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } void ContextInfluences::weightChanged( int index, double weight ) { if ( !m_change ) { m_update = true; if ( weight < 0.0 ) { weight = 0.0; } if ( weight > 1.0 ) { weight = 1.0; } int joint = m_joints[ index ]; log_debug( "setting joint %d weight to %f\n", joint, weight ); std::list l; m_model->getSelectedPositions( l ); std::list::iterator it; for ( it = l.begin(); it != l.end(); it++ ) { m_model->setPositionInfluenceType( *it, joint, Model::IT_Custom ); m_model->setPositionInfluenceWeight( *it, joint, weight ); } m_model->operationComplete( tr( "Change Influence Weight", "operation complete" ).toUtf8() ); updateRemainders(); emit panelChange(); m_update = false; } } void ContextInfluences::typeChanged( int index ) { if ( !m_change ) { m_update = true; int joint = m_joints[ index ]; QComboBox * typeValue = m_weight1; switch ( index ) { case 1: typeValue = m_weight2; break; case 2: typeValue = m_weight3; break; case 3: typeValue = m_weight4; break; default: break; } Model::InfluenceTypeE type = Model::IT_Auto; switch ( typeValue->currentIndex() ) { case 0: // Not really a valid selection, return m_update = false; return; case 1: type = Model::IT_Custom; break; case 2: type = Model::IT_Auto; break; case 3: type = Model::IT_Remainder; break; default: break; } log_debug( "setting joint %d type to %d\n", joint, (int) type ); std::list l; m_model->getSelectedPositions( l ); int weight = 0; std::list::iterator it; for ( it = l.begin(); it != l.end(); it++ ) { m_model->setPositionInfluenceType( *it, joint, type ); if ( type == Model::IT_Auto ) { double w = m_model->calculatePositionInfluenceWeight( *it, joint ); m_model->setPositionInfluenceWeight( *it, joint, w ); weight += (int) (w * 100.0); } else { m_model->setPositionInfluenceWeight( *it, joint, (double) m_jclist[ joint ].weight / 100.0 ); } } if ( type == Model::IT_Auto ) { m_jclist[ joint ].weight = weight / m_jclist[ joint ].count; } m_jclist[ joint ].typeIndex = type + 1; m_change = true; updateWeightField( index, true, m_jclist[ joint ].typeIndex, m_jclist[ joint ].weight ); updateRemainders(); m_change = false; m_model->operationComplete( tr( "Change Influence Type", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } void ContextInfluences::joint1Changed() { int index = 0; jointChanged( index, m_joints[ index ], m_joint1->currentIndex() - 1); } void ContextInfluences::joint2Changed() { int index = 1; jointChanged( index, m_joints[ index ], m_joint2->currentIndex() - 1); } void ContextInfluences::joint3Changed() { int index = 2; jointChanged( index, m_joints[ index ], m_joint3->currentIndex() - 1); } void ContextInfluences::joint4Changed() { int index = 3; jointChanged( index, m_joints[ index ], m_joint4->currentIndex() - 1); } void ContextInfluences::type1Changed() { int index = 0; typeChanged( index ); } void ContextInfluences::type2Changed() { int index = 1; typeChanged( index ); } void ContextInfluences::type3Changed() { int index = 2; typeChanged( index ); } void ContextInfluences::type4Changed() { int index = 3; typeChanged( index ); } void ContextInfluences::weight1Changed( const QString & weight ) { int index = 0; if ( weight.size() != 0 && weight[0].isDigit() ) { weightChanged( index, weight.toDouble() / 100.0 ); } } void ContextInfluences::weight2Changed( const QString & weight ) { int index = 1; if ( weight.size() != 0 && weight[0].isDigit() ) { weightChanged( index, weight.toDouble() / 100.0 ); } } void ContextInfluences::weight3Changed( const QString & weight ) { int index = 2; if ( weight.size() != 0 && weight[0].isDigit() ) { weightChanged( index, weight.toDouble() / 100.0 ); } } void ContextInfluences::weight4Changed( const QString & weight ) { int index = 3; if ( weight.size() != 0 && weight[0].isDigit() ) { weightChanged( index, weight.toDouble() / 100.0 ); } } void ContextInfluences::updateRemainders() { for ( int index = 0; index < Model::MAX_INFLUENCES; index++ ) { QComboBox * weightBox = m_weight1; switch ( index ) { case 0: weightBox = m_weight1; break; case 1: weightBox = m_weight2; break; case 2: weightBox = m_weight3; break; case 3: weightBox = m_weight4; break; default: break; } if ( weightBox->currentIndex() - 1 == Model::IT_Remainder ) { int w = getRemainderWeight( m_joints[ index ] ); log_debug( "updating box %d with remaining weight %d\n", index, w ); updateWeightField( index, weightBox->isEnabled(), weightBox->currentIndex(), w ); } } } void ContextInfluences::updateWeightField( int index, bool enabled, int type, int weight ) { QComboBox * weightBox = m_weight1; switch ( index ) { case 0: weightBox = m_weight1; break; case 1: weightBox = m_weight2; break; case 2: weightBox = m_weight3; break; case 3: weightBox = m_weight4; break; default: break; } weightBox->setItemText( 0, tr("", "multiple types of bone joint influence") ); weightBox->setItemText( 1, tr("Custom", "bone joint influence") ); weightBox->setItemText( 2, tr("Auto", "bone joint influence") ); weightBox->setItemText( 3, tr("Remainder", "bone joint influence") ); if ( enabled ) { QString typeStr; switch ( type ) { case 0: typeStr = tr("", "multiple types of bone joint influence"); break; case 1: typeStr.sprintf( "%d", weight ); break; case 2: typeStr = tr("Auto: %1").arg( weight); break; case 3: typeStr = tr("Rem: %1").arg(weight); break; default: break; } weightBox->setItemText( type, typeStr ); weightBox->setCurrentIndex( type ); weightBox->setEnabled( true ); } else { weightBox->setCurrentIndex( 0 ); weightBox->setEnabled( false ); } // Update remainder fields switch ( index ) { case 0: weightBox = m_weight1; break; case 1: weightBox = m_weight2; break; case 2: weightBox = m_weight3; break; case 3: weightBox = m_weight4; break; default: break; } } int ContextInfluences::getRemainderWeight( int joint ) { log_debug( "getting remainder weight for joint %d\n" ); if ( joint >= 0 && joint < (int) m_model->getBoneJointCount() ) { list< Model::Position > plist; list< Model::Position >::iterator pit; Model::InfluenceList ilist; Model::InfluenceList::iterator iit; m_model->getSelectedPositions( plist ); double weight = 0.0; int count = 0; for ( pit = plist.begin(); pit != plist.end(); pit++ ) { m_model->getPositionInfluences( (*pit), ilist ); for ( iit = ilist.begin(); iit != ilist.end(); iit++ ) { if ( (*iit).m_type == Model::IT_Remainder && (*iit).m_boneId == joint ) { weight += (*iit).m_weight; count++; } } } if ( count > 0 ) { return (int) ((weight * 100.0) / (double) count); } } return 0; } mm3d-master/src/implui/contextinfluences.h000066400000000000000000000051361324021725400212130ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTINFLUENCES_H #define __CONTEXTINFLUENCES_H #include "contextinfluences.base.h" #include #include "contextwidget.h" #include "model.h" class ContextInfluences : public QWidget, public Ui::ContextInfluencesBase, public ContextWidget { Q_OBJECT public: ContextInfluences( QWidget * parent ); virtual ~ContextInfluences(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Influence slots void joint1Changed(); void joint2Changed(); void joint3Changed(); void joint4Changed(); void type1Changed(); void type2Changed(); void type3Changed(); void type4Changed(); void weight1Changed( const QString & ); void weight2Changed( const QString & ); void weight3Changed( const QString & ); void weight4Changed( const QString & ); protected: class JointCount { public: JointCount(); bool inList; int count; int typeCount[ Model::IT_MAX ]; int typeIndex; int weight; }; typedef std::vector< JointCount > JointCountList; void jointChanged( int index, int oldJoint, int newJoint ); void weightChanged( int index, double weight ); void typeChanged( int index ); void updateRemainders(); void updateWeightField( int index, bool enabled, int type, int weight ); int getRemainderWeight( int joint ); Model * m_model; bool m_change; bool m_update; int m_joints[4]; JointCountList m_jclist; }; #endif // __CONTEXTINFLUENCES_H mm3d-master/src/implui/contextname.cc000066400000000000000000000053331324021725400201350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextname.h" #include "model.h" #include #include ContextName::ContextName( QWidget * parent ) : QWidget( parent ), m_change( false ), m_update( false ) { setupUi( this ); } ContextName::~ContextName() { } void ContextName::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextName::modelChanged( int changeBits ) { if ( !m_update ) { m_change = true; unsigned bcount = m_model->getBoneJointCount(); for ( unsigned b = 0; b < bcount; b++ ) { if ( m_model->isBoneJointSelected( b ) ) { m_name->setText( QString::fromUtf8( m_model->getBoneJointName( b ) ) ); break; } } unsigned pcount = m_model->getPointCount(); for ( unsigned p = 0; p < pcount; p++ ) { if ( m_model->isPointSelected( p ) ) { m_name->setText( QString::fromUtf8( m_model->getPointName( p ) ) ); break; } } m_change = false; } } void ContextName::textChangedEvent( const QString & nameStr ) { if ( !m_change ) { m_update = true; // Change model based on text field input unsigned bcount = m_model->getBoneJointCount(); for ( unsigned b = 0; b < bcount; b++ ) { if ( m_model->isBoneJointSelected( b ) ) { m_model->setBoneJointName( b, (const char*) nameStr.toUtf8() ); break; } } unsigned pcount = m_model->getPointCount(); for ( unsigned p = 0; p < pcount; p++ ) { if ( m_model->isPointSelected( p ) ) { m_model->setPointName( p, (const char*) nameStr.toUtf8() ); break; } } m_model->operationComplete( tr( "Rename", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } mm3d-master/src/implui/contextname.h000066400000000000000000000030641324021725400177760ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTNAME_H #define __CONTEXTNAME_H #include "contextname.base.h" #include "contextwidget.h" #include class Model; class ContextName : public QWidget, public Ui::ContextNameBase, public ContextWidget { Q_OBJECT public: ContextName( QWidget * parent ); virtual ~ContextName(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Position slots void textChangedEvent( const QString & ); protected: Model * m_model; bool m_change; bool m_update; }; #endif // __CONTEXTNAME_H mm3d-master/src/implui/contextpanel.cc000066400000000000000000000173771324021725400203270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextpanel.h" #include "viewpanel.h" #include "contextname.h" #include "contextposition.h" #include "contextrotation.h" #include "contextgroup.h" #include "contextinfluences.h" #include "contextprojection.h" #include "log.h" #include #include #include #include ContextPanel::ContextPanel( QMainWindow * parent, ViewPanel * panel, ContextPanelObserver * ob ) : QDockWidget( tr( "Properties", "Window title" ), parent ), m_model( NULL ), m_observer( ob ), m_panel( panel ), m_mainWidget( new QWidget( parent ) ), m_spacer( NULL ) { setWidget( m_mainWidget ); m_layout = new QBoxLayout( QBoxLayout::TopToBottom, m_mainWidget ); } ContextPanel::~ContextPanel() { } void ContextPanel::setModel( Model * model ) { ContextWidgetList::iterator it; for ( it = m_widgets.begin(); it!= m_widgets.end(); it++ ) { delete *it; } m_widgets.clear(); if ( m_spacer ) { delete m_spacer; m_spacer = NULL; } if ( m_model != model ) { model->addObserver( this ); } m_model = model; modelChanged( Model::ChangeAll ); } void ContextPanel::modelChanged( int changeBits ) { if ( this->isVisible() ) { log_debug( "modelChanged()\n" ); setUpdatesEnabled( false ); ContextWidgetList::iterator it; // If the panel caused the change, update all // panels and return for ( it = m_widgets.begin(); it!= m_widgets.end(); it++ ) { if ( (*it)->isUpdating() ) { for ( it = m_widgets.begin(); it!= m_widgets.end(); it++ ) { (*it)->modelChanged( changeBits ); } setUpdatesEnabled( true ); return; } } // If selection didn't change, just send an update if ( !(changeBits & (Model::SelectionChange | Model::AnimationMode)) ) { for ( it = m_widgets.begin(); it!= m_widgets.end(); it++ ) { (*it)->modelChanged( changeBits ); } setUpdatesEnabled( true ); return; } log_debug( "deleting and re-creating (%08X)\n", changeBits ); // Otherwise, delete panels and recreate // TODO: may optimize by not deleting and re-creating, need to // be smarter about changes for ( it = m_widgets.begin(); it!= m_widgets.end(); it++ ) { delete *it; } m_widgets.clear(); { if ( Model::ANIMMODE_NONE == m_model->getAnimationMode() && (m_model->getSelectedBoneJointCount() + m_model->getSelectedPointCount()) == 1 ) { ContextName * name = new ContextName( m_mainWidget ); name->setModel( m_model ); m_layout->addWidget( name ); name->show(); connect( name, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( name ); } } // Position should always be visible ContextPosition * pos = new ContextPosition( m_mainWidget ); pos->setModel( m_model ); m_layout->addWidget( pos ); pos->show(); connect( pos, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( pos ); { // Only allow points in None and Frame // Only allow joints (for keyframe) in Skel int pcount = m_model->getSelectedPointCount(); int jcount = m_model->getSelectedBoneJointCount(); if ( ((pcount == 1) && (jcount == 0) && m_model->getAnimationMode() != Model::ANIMMODE_SKELETAL ) || ((jcount == 1) && (pcount == 0) && m_model->getAnimationMode() == Model::ANIMMODE_SKELETAL ) ) { ContextRotation * rot = new ContextRotation( m_mainWidget ); rot->setModel( m_model ); m_layout->addWidget( rot ); rot->show(); connect( rot, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( rot ); } } unsigned int tcount = m_model->getTriangleCount(); for ( unsigned int t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { ContextGroup * grp = new ContextGroup( m_mainWidget, m_observer ); grp->setModel( m_model ); m_layout->addWidget( grp ); grp->show(); connect( grp, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( grp ); break; } } unsigned int pcount = m_model->getProjectionCount(); for ( unsigned int p = 0; p < pcount; p++ ) { if ( m_model->isProjectionSelected( p ) ) { ContextProjection * prj = new ContextProjection( m_mainWidget, m_observer ); prj->setModel( m_model ); m_layout->addWidget( prj ); prj->show(); connect( prj, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( prj ); break; } } // Only show influences if there are influences to show if ( m_model->getBoneJointCount() > 0 && m_model->getAnimationMode() == Model::ANIMMODE_NONE ) { bool showInfluences = false; unsigned pointCount = m_model->getPointCount(); for ( unsigned n = 0; !showInfluences && n < pointCount; n++ ) { if ( m_model->isPointSelected( n ) ) { showInfluences = true; } } unsigned vcount = m_model->getVertexCount(); for ( unsigned v = 0; !showInfluences && v < vcount; v++ ) { if ( m_model->isVertexSelected( v ) ) { showInfluences = true; } } if ( showInfluences ) { ContextInfluences * prj = new ContextInfluences( m_mainWidget ); prj->setModel( m_model ); m_layout->addWidget( prj ); prj->show(); connect( prj, SIGNAL(panelChange()), m_panel, SLOT(modelUpdatedEvent())); m_widgets.push_back( prj ); } } m_spacer = new QSpacerItem( 0, 0, QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ); setUpdatesEnabled( true ); } } void ContextPanel::show() { QDockWidget::show(); // this is causing a segfault on dock/undock because the widgets // are being destroyed and re-created. The solution is to call setModel // explicitly whenever the window is shown (this only happens in viewwin.cc) //setModel( m_model ) } void ContextPanel::close() { hide(); // Do hide instead } void ContextPanel::hide() { log_debug( "ContextPanel::hide()\n" ); QDockWidget::hide(); } void ContextPanel::contextMenuEvent( QContextMenuEvent * e ) { e->ignore(); } void ContextPanel::closeEvent( QCloseEvent * e ) { emit panelHidden(); } mm3d-master/src/implui/contextpanel.h000066400000000000000000000037331324021725400201600ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTPANEL_H #define __CONTEXTPANEL_H #include "contextpanelobserver.h" #include "contextwidget.h" #include "model.h" #include #include class QContextMenuEvent; class QCloseEvent; class QBoxLayout; class QSpacerItem; class ViewPanel; class ContextPanelObserver; class ContextPanel : public QDockWidget, public Model::Observer { Q_OBJECT public: ContextPanel( QMainWindow * parent, ViewPanel * panel, ContextPanelObserver * ob ); virtual ~ContextPanel(); // QDockWidget methods public slots: void show(); void close(); void hide(); void closeEvent( QCloseEvent * e ); void setModel( Model * m ); // Model::Observer methods void modelChanged( int changeBits ); signals: void panelHidden(); protected: void contextMenuEvent( QContextMenuEvent * e ); Model * m_model; ContextPanelObserver * m_observer; ViewPanel * m_panel; QWidget * m_mainWidget; QBoxLayout * m_layout; QSpacerItem * m_spacer; ContextWidgetList m_widgets; }; #endif // __CONTEXTPANEL_H mm3d-master/src/implui/contextposition.cc000066400000000000000000000105751324021725400210650ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextposition.h" #include "model.h" #include #include ContextPosition::ContextPosition( QWidget * parent ) : QWidget( parent ), m_change( false ), m_update( false ) { setupUi( this ); } ContextPosition::~ContextPosition() { } void ContextPosition::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextPosition::modelChanged( int changeBits ) { if ( !m_update ) { m_change = true; // Update coordinates in text fields bool first = true; double cmin[3]; double cmax[3]; double coords[3]; int i; for ( i = 0; i < 3; i++ ) { cmin[i] = 0.0; cmax[i] = 0.0; } /* unsigned vcount = m_model->getVertexCount(); for ( unsigned v = 0; v < vcount; v++ ) { if ( m_model->isVertexSelected( v ) ) { m_model->getVertexCoords( v, coords ); if ( !first ) { for ( i = 0; i < 3; i++ ) { if ( coords[i] < cmin[i] ) cmin[i] = coords[i]; if ( coords[i] > cmax[i] ) cmax[i] = coords[i]; } } else { first = false; for ( i = 0; i < 3; i++ ) { cmin[i] = coords[i]; cmax[i] = coords[i]; } } } } unsigned pcount = m_model->getPointCount(); */ std::list posList; m_model->getSelectedPositions( posList ); std::list::iterator it; for ( it = posList.begin(); it != posList.end(); it++ ) { m_model->getPositionCoords( *it, coords ); if ( !first ) { for ( i = 0; i < 3; i++ ) { if ( coords[i] < cmin[i] ) cmin[i] = coords[i]; if ( coords[i] > cmax[i] ) cmax[i] = coords[i]; } } else { first = false; for ( i = 0; i < 3; i++ ) { cmin[i] = coords[i]; cmax[i] = coords[i]; } } } for ( i = 0; i < 3; i++ ) { m_coords[i] = (cmin[i] + cmax[i]) / 2.0; } QString str; str.sprintf( "%f", m_coords[0] ); m_xValue->setText( str ); str.sprintf( "%f", m_coords[1] ); m_yValue->setText( str ); str.sprintf( "%f", m_coords[2] ); m_zValue->setText( str ); str.sprintf( "%g, %g, %g", cmax[0]-cmin[0], cmax[1]-cmin[1], cmax[2]-cmin[2] ); m_dimensionsValue->setText( str ); m_change = false; } } void ContextPosition::updatePosition() { if ( !m_change ) { m_update = true; // Change model based on text field input double coords[3]; double trans[3]; coords[0] = m_xValue->text().toDouble(); coords[1] = m_yValue->text().toDouble(); coords[2] = m_zValue->text().toDouble(); trans[0] = coords[0] - m_coords[0]; trans[1] = coords[1] - m_coords[1]; trans[2] = coords[2] - m_coords[2]; m_coords[0] = coords[0]; m_coords[1] = coords[1]; m_coords[2] = coords[2]; Matrix m; m.setTranslation( trans[0], trans[1], trans[2] ); m_model->translateSelected( m ); m_model->operationComplete( tr( "Set Position", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } mm3d-master/src/implui/contextposition.h000066400000000000000000000031341324021725400207200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTPOSITION_H #define __CONTEXTPOSITION_H #include "contextposition.base.h" #include #include "contextwidget.h" class Model; class ContextPosition : public QWidget, public Ui::ContextPositionBase, public ContextWidget { Q_OBJECT public: ContextPosition( QWidget * parent ); virtual ~ContextPosition(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Position slots void updatePosition(); protected: Model * m_model; double m_coords[3]; bool m_change; bool m_update; }; #endif // __CONTEXTPOSITION_H mm3d-master/src/implui/contextprojection.cc000066400000000000000000000053041324021725400213670ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextprojection.h" #include "model.h" #include "contextpanelobserver.h" #include "groupwin.h" #include "texwin.h" #include #include #include #include ContextProjection::ContextProjection( QWidget * parent, ContextPanelObserver * ob ) : QWidget( parent ), m_model( NULL ), m_observer( ob ), m_change( false ), m_update( false ) { setupUi( this ); } ContextProjection::~ContextProjection() { } void ContextProjection::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextProjection::modelChanged( int changeBits ) { // Only change if it's a group change or a selection change if ( (changeBits & Model::AddOther) || (changeBits & Model::SelectionChange ) ) { if ( !m_update ) { m_change = true; // Update projection fields unsigned int pcount = m_model->getProjectionCount(); for ( unsigned int p = 0; p < pcount; p++ ) { if ( m_model->isProjectionSelected( p ) ) { m_typeValue->setCurrentIndex( m_model->getProjectionType( p ) ); break; } } m_change = false; } } } void ContextProjection::typeChanged() { if ( !m_change ) { m_update = true; int type = m_typeValue->currentIndex(); unsigned pcount = m_model->getProjectionCount(); for ( unsigned p = 0; p < pcount; p++ ) { if ( m_model->isProjectionSelected( p ) ) { m_model->setProjectionType( p, type ); } } m_model->operationComplete( tr( "Set Projection Type", "operation complete" ).toUtf8() ); emit panelChange(); m_update = false; } } void ContextProjection::projectionPropertiesClicked() { m_observer->showProjectionEvent(); } mm3d-master/src/implui/contextprojection.h000066400000000000000000000033331324021725400212310ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTPROJECTION_H #define __CONTEXTPROJECTION_H #include "contextprojection.base.h" #include #include "contextwidget.h" class ContextPanelObserver; class Model; class ContextProjection : public QWidget, public Ui::ContextProjectionBase, public ContextWidget { Q_OBJECT public: ContextProjection( QWidget * parent, ContextPanelObserver * ob ); virtual ~ContextProjection(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Projection slots void typeChanged(); void projectionPropertiesClicked(); protected: Model * m_model; ContextPanelObserver * m_observer; bool m_change; bool m_update; }; #endif // __CONTEXTPROJECTION_H mm3d-master/src/implui/contextrotation.cc000066400000000000000000000104651324021725400210560ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "contextrotation.h" #include "model.h" #include #include ContextRotation::ContextRotation( QWidget * parent ) : QWidget( parent ), m_change( false ), m_update( false ) { setupUi( this ); } ContextRotation::~ContextRotation() { } void ContextRotation::setModel( Model * m ) { m_model = m; modelChanged( ~0 ); } void ContextRotation::modelChanged( int changeBits ) { if ( !m_update ) { m_change = true; bool searching = true; // Update coordinates in text fields double rad[3]; memset( rad, 0, sizeof(rad) ); unsigned int pcount = m_model->getPointCount(); for ( unsigned int p = 0; searching && p < pcount; p++ ) { if ( m_model->isPointSelected( p ) ) { searching = false; m_model->getPointRotation( p, rad ); } } if ( m_model->getAnimationMode() == Model::ANIMMODE_SKELETAL ) { unsigned int bcount = m_model->getBoneJointCount(); for ( unsigned int b = 0; searching && b < bcount; b++ ) { if ( m_model->isBoneJointSelected(b) ) { int anim = m_model->getCurrentAnimation(); int frame = m_model->getCurrentAnimationFrame(); if ( m_model->getSkelAnimKeyframe( anim, frame, b, true, rad[0], rad[1], rad[2] ) ) { searching = false; } } } } for ( int i = 0; i < 3; i++ ) { rad[i] = rad[i] / PIOVER180; } QString str; str.sprintf( "%f", rad[0] ); m_xValue->setText( str ); str.sprintf( "%f", rad[1] ); m_yValue->setText( str ); str.sprintf( "%f", rad[2] ); m_zValue->setText( str ); this->setEnabled( searching ? false : true ); m_change = false; } } void ContextRotation::updateRotation() { if ( !m_change ) { m_update = true; // Change model based on text field input double rad[3]; rad[0] = m_xValue->text().toDouble(); rad[1] = m_yValue->text().toDouble(); rad[2] = m_zValue->text().toDouble(); rad[0] = rad[0] * PIOVER180; rad[1] = rad[1] * PIOVER180; rad[2] = rad[2] * PIOVER180; bool searching = true; unsigned int pcount = m_model->getPointCount(); for ( unsigned int p = 0; searching && p < pcount; p++ ) { if ( m_model->isPointSelected( p ) ) { searching = false; m_model->setPointRotation( p, rad ); } } if ( m_model->getAnimationMode() == Model::ANIMMODE_SKELETAL ) { unsigned int bcount = m_model->getBoneJointCount(); for ( unsigned int b = 0; searching && b < bcount; b++ ) { if ( m_model->isBoneJointSelected(b) ) { int anim = m_model->getCurrentAnimation(); int frame = m_model->getCurrentAnimationFrame(); if ( m_model->setSkelAnimKeyframe( anim, frame, b, true, rad[0], rad[1], rad[2] ) ) { searching = false; m_model->setCurrentAnimationFrame( frame ); // Force re-animate } } } } if ( !searching ) { m_model->operationComplete( tr( "Set Rotation", "operation complete" ).toUtf8() ); emit panelChange(); } m_update = false; } } mm3d-master/src/implui/contextrotation.h000066400000000000000000000031011324021725400207050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CONTEXTROTATION_H #define __CONTEXTROTATION_H #include "contextrotation.base.h" #include #include "contextwidget.h" class Model; class ContextRotation : public QWidget, public Ui::ContextRotationBase, public ContextWidget { Q_OBJECT public: ContextRotation( QWidget * parent ); virtual ~ContextRotation(); // ContextWidget methods void setModel( Model * ); void modelChanged( int changeBits ); bool isUpdating() { return m_update; }; signals: void panelChange(); public slots: // Rotation slots void updateRotation(); protected: Model * m_model; bool m_change; bool m_update; }; #endif // __CONTEXTROTATION_H mm3d-master/src/implui/extrudewin.cc000066400000000000000000000231031324021725400200010ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "extrudewin.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "decalmgr.h" #include "3dmprefs.h" #include "helpwin.h" #include #include #include using std::list; using std::map; ExtrudeWin::ExtrudeWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setupUi( this ); setModal( true ); if ( g_prefs.exists( "ui_extrude_makebackfaces" ) ) { int val = g_prefs( "ui_extrude_makebackfaces" ).intValue(); if ( val != 0 ) { m_backFaceCheckbox->setChecked( true ); } else { m_backFaceCheckbox->setChecked( false ); } } QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } ExtrudeWin::~ExtrudeWin() { } void ExtrudeWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_commands.html#extrude", true ); win->show(); } void ExtrudeWin::absoluteExtrudeEvent() { m_sides.clear(); m_evMap.clear(); model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Extrude complete").toUtf8() ); // get extrude arguments double x = m_xEdit->text().toDouble(); double y = m_yEdit->text().toDouble(); double z = m_zEdit->text().toDouble(); list faces; m_model->getSelectedTriangles( faces ); list vertices; m_model->getSelectedVertices( vertices ); log_debug( "extruding %d faces on %f,%f,%f\n", faces.size(), x, y, z ); // Find edges (sides with count==1) list::iterator it; for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); } for ( int t = 0; t < (3 - 1); t++ ) { addSide( v[t], v[t+1] ); } addSide( v[0], v[2] ); } // make extruded vertices and create a map from old vertices // to new vertices for ( it = vertices.begin(); it != vertices.end(); it++ ) { double coord[3]; m_model->getVertexCoords( *it, coord ); coord[0] += x; coord[1] += y; coord[2] += z; unsigned i = m_model->addVertex( coord[0], coord[1], coord[2] ); m_evMap[*it] = i; log_debug( "added vertex %d for %d at %f,%f,%f\n", m_evMap[*it], *it, coord[0], coord[1], coord[2] ); } // Add faces for edges for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); } for ( int t = 0; t < (3 - 1); t++ ) { if ( sideIsEdge( v[t], v[t+1] ) ) { makeFaces( v[t], v[t+1] ); } } if ( sideIsEdge( v[2], v[0] ) ) { makeFaces( v[2], v[0] ); } } // Map selected faces onto extruded vertices for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned tri = *it; int v1 = m_model->getTriangleVertex( tri, 0 ); int v2 = m_model->getTriangleVertex( tri, 1 ); int v3 = m_model->getTriangleVertex( tri, 2 ); if ( m_backFaceCheckbox->isChecked() ) { int newTri = m_model->addTriangle( v1, v2, v3 ); m_model->invertNormals( newTri ); } log_debug( "face %d uses vertices %d,%d,%d\n", *it, v1, v2, v3 ); m_model->setTriangleVertices( tri, m_evMap[ m_model->getTriangleVertex( tri, 0 ) ], m_evMap[ m_model->getTriangleVertex( tri, 1 ) ], m_evMap[ m_model->getTriangleVertex( tri, 2 ) ] ); log_debug( "moved face %d to vertices %d,%d,%d\n", *it, m_model->getTriangleVertex( tri, 0 ), m_model->getTriangleVertex( tri, 1 ), m_model->getTriangleVertex( tri, 2 ) ); } // Update face selection ExtrudedVertexMap::iterator evit; for ( evit = m_evMap.begin(); evit != m_evMap.end(); evit++ ) { m_model->unselectVertex( (*evit).first ); m_model->selectVertex( (*evit).second ); } m_model->deleteOrphanedVertices(); m_model->operationComplete( tr( "Extrude", "operation complete" ).toUtf8() ); DecalManager::getInstance()->modelUpdated( m_model ); } void ExtrudeWin::normalExtrudeEvent() { /* m_sides.clear(); m_evMap.clear(); double magnitude = m_normalEdit->text().toDouble(); list faces = m_model->getSelectedTriangles(); list vertices = m_model->getSelectedVertices(); // Find edges (sides with count==1) list::iterator it; for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); // Capture normal while we're here // Note that if normals aren't smoothed the extrude may not // have the intended effect VertexNormal vn; m_model->getNormal( *it, t, vn.val ); m_vnMap[ v[t] ] = vn; log_debug( "vertex %d normals: %f,%f,%f\n", v[t], vn.val[0], vn.val[1], vn.val[2] ); } for ( int t = 0; t < (3 - 1); t++ ) { addSide( v[t], v[t+1] ); } addSide( v[0], v[2] ); } // make extruded vertices and create a map from old vertices // to new vertices for ( it = vertices.begin(); it != vertices.end(); it++ ) { double coord[3]; m_model->getVertexCoords( *it, coord ); VertexNormal vn = m_vnMap[ *it ]; coord[0] += vn.val[0] * magnitude; coord[1] += vn.val[1] * magnitude; coord[2] += vn.val[2] * magnitude; unsigned i = m_model->addVertex( coord[0], coord[1], coord[2] ); m_evMap[*it] = i; log_debug( "added vertex %d for %d at %f,%f,%f\n", m_evMap[*it], *it, coord[0], coord[1], coord[2] ); } // Add faces for edges for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); } for ( int t = 0; t < (3 - 1); t++ ) { if ( sideIsEdge( v[t], v[t+1] ) ) { makeFaces( v[t], v[t+1] ); } } if ( sideIsEdge( v[2], v[0] ) ) { makeFaces( v[2], v[0] ); } } // Map selected faces onto extruded vertices for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned tri = *it; log_debug( "face %d uses vertices %d,%d,%d\n", *it, m_model->getTriangleVertex( tri, 0 ), m_model->getTriangleVertex( tri, 1 ), m_model->getTriangleVertex( tri, 2 ) ); m_model->setTriangleVertices( tri, m_evMap[ m_model->getTriangleVertex( tri, 0 ) ], m_evMap[ m_model->getTriangleVertex( tri, 1 ) ], m_evMap[ m_model->getTriangleVertex( tri, 2 ) ] ); log_debug( "moved face %d to vertices %d,%d,%d\n", *it, m_model->getTriangleVertex( tri, 0 ), m_model->getTriangleVertex( tri, 1 ), m_model->getTriangleVertex( tri, 2 ) ); } // Update face selection ExtrudedVertexMap::iterator evit; for ( evit = m_evMap.begin(); evit != m_evMap.end(); evit++ ) { m_model->unselectVertex( (*evit).first ); m_model->selectVertex( (*evit).second ); } m_model->operationComplete(); DecalManager::getInstance()->modelUpdated( m_model ); */ } void ExtrudeWin::backFacesChanged( bool o ) { g_prefs( "ui_extrude_makebackfaces" ) = (o ? 1 : 0); } void ExtrudeWin::makeFaces( unsigned a, unsigned b ) { unsigned a2 = m_evMap[a]; unsigned b2 = m_evMap[b]; m_model->addTriangle( b, b2, a2 ); m_model->addTriangle( a2, a, b ); } void ExtrudeWin::addSide( unsigned a, unsigned b ) { // Make sure a < b to simplify comparison below if ( b < a ) { unsigned c = a; a = b; b = c; } // Find existing side (if any) and increment count SideList::iterator it; for ( it = m_sides.begin(); it != m_sides.end(); it++ ) { if ( (*it).a == a && (*it).b == b ) { (*it).count++; log_debug( "side (%d,%d) = %d\n", a, b, (*it).count ); return; } } // Not found, add new side with a count of 1 SideT s; s.a = a; s.b = b; s.count = 1; log_debug( "side (%d,%d) = %d\n", a, b, s.count ); m_sides.push_back( s ); } bool ExtrudeWin::sideIsEdge( unsigned a, unsigned b ) { // Make sure a < b to simplify comparison below if ( b < a ) { unsigned c = a; a = b; b = c; } SideList::iterator it; for ( it = m_sides.begin(); it != m_sides.end(); it++ ) { if ( (*it).a == a && (*it).b == b ) { if ( (*it).count == 1 ) { return true; } else { return false; } } } return false; } mm3d-master/src/implui/extrudewin.h000066400000000000000000000037351324021725400176540ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __EXTRUDEWIN_H #define __EXTRUDEWIN_H #include "extrudewin.base.h" #include #include #include class Model; class ExtrudeWin : public QDialog, public Ui::ExtrudeWinBase { Q_OBJECT public: ExtrudeWin( Model *, QWidget * parent = NULL ); virtual ~ExtrudeWin(); public slots: void helpNowEvent(); void absoluteExtrudeEvent(); void normalExtrudeEvent(); void backFacesChanged( bool ); protected: struct _Side_t { unsigned a; unsigned b; int count; }; typedef struct _Side_t SideT; typedef struct { float val[3]; } VertexNormal; typedef std::list SideList; typedef std::map ExtrudedVertexMap; typedef std::map VertexNormalMap; void makeFaces( unsigned a, unsigned b ); void addSide( unsigned a, unsigned b ); bool sideIsEdge( unsigned a, unsigned b ); Model * m_model; SideList m_sides; ExtrudedVertexMap m_evMap; VertexNormalMap m_vnMap; }; #endif // __EXTRUDEWIN_H mm3d-master/src/implui/globalmenubar.cc000066400000000000000000000127571324021725400204320ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2018 Zack Middleton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "globalmenubar.h" #include "keycfg.h" #include "3dmprefs.h" #include "model.h" #include "viewwin.h" #include "pluginwin.h" #include "helpwin.h" #include "licensewin.h" #include "aboutwin.h" // Default menu bar on macOS when no window is open or windows are minimized. // Based on menu in viewwin.cc GlobalMenuBar::GlobalMenuBar() { #ifdef HAVE_LUALIB QMenu *menu; #endif QAction *action; m_menuBar = new QMenuBar( NULL ); m_fileMenu = m_menuBar->addMenu( tr("&File", "menu bar") ); m_fileMenu->addAction( tr("New", "File|New"), this, SLOT(newModelEvent()), g_keyConfig.getKey( "viewwin_file_new" ) ); m_fileMenu->addAction( tr("Open...", "File|Open"), this, SLOT(openModelEvent()), g_keyConfig.getKey( "viewwin_file_open" ) ); // Disable items that require a window action = m_fileMenu->addAction( tr("Save", "File|Save"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_save" ) ); action->setEnabled( false ); action = m_fileMenu->addAction( tr("Save As...", "File|Save As"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_save_as" ) ); action->setEnabled( false ); action = m_fileMenu->addAction( tr("Export...", "File|Export"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_export" ) ); action->setEnabled( false ); action = m_fileMenu->addAction( tr("Export Selected...", "File|Export Selected"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_export_selected" ) ); action->setEnabled( false ); #ifdef HAVE_LUALIB action = m_fileMenu->addAction( tr("Run Script...", "File|Run Script"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_run_script" ) ); action->setEnabled( false ); m_scriptMruMenu = m_fileMenu->addMenu( tr("Recent Scripts", "File|Recent Script") ); connect( m_scriptMruMenu, SIGNAL(aboutToShow()), this, SLOT(fillScriptMruMenuDisabled()) ); #endif // HAVE_LUALIB m_fileMenu->addSeparator(); m_mruMenu = m_fileMenu->addMenu( tr("Recent Models", "File|Recent Models") ); connect( m_mruMenu, SIGNAL(aboutToShow()), this, SLOT(fillMruMenu()) ); connect( m_mruMenu, SIGNAL(triggered(QAction*)), this, SLOT(openMru(QAction*)) ); m_fileMenu->addSeparator(); m_fileMenu->addAction( tr("Plugins...", "File|Plugins"), this, SLOT(pluginWindowEvent()), g_keyConfig.getKey( "viewwin_file_plugins" ) ); m_fileMenu->addSeparator(); // Disable items that require a window action = m_fileMenu->addAction( tr("Close", "File|Close"), this, SLOT(dummyEvent()), g_keyConfig.getKey( "viewwin_file_close" ) ); action->setEnabled( false ); m_fileMenu->addAction( tr("Quit", "File|Quit"), this, SLOT(quitEvent()), g_keyConfig.getKey( "viewwin_file_quit" ) ); m_helpMenu = m_menuBar->addMenu( tr("&Help", "menu bar") ); m_helpMenu->addAction( tr("Contents...", "Help|Contents"), this, SLOT(helpWindowEvent()), g_keyConfig.getKey( "viewwin_help_contents" ) ); m_helpMenu->addAction( tr("License...", "Help|License"), this, SLOT(licenseWindowEvent()), g_keyConfig.getKey( "viewwin_help_license" ) ); m_helpMenu->addAction( tr("About...", "Help|About"), this, SLOT(aboutWindowEvent()), g_keyConfig.getKey( "viewwin_help_about" ) ); } GlobalMenuBar::~GlobalMenuBar() { delete m_menuBar; } void GlobalMenuBar::openModelEvent() { ViewWindow::openModelDialog(); } void GlobalMenuBar::newModelEvent() { ViewWindow * win = new ViewWindow( new Model, NULL ); win->getSaved(); // Just so I don't have a warning } void GlobalMenuBar::quitEvent() { if ( ViewWindow::closeAllWindows() ) { qApp->quit(); } } void GlobalMenuBar::helpWindowEvent() { HelpWin * win = new HelpWin(); win->show(); } void GlobalMenuBar::pluginWindowEvent() { // pluginWin will delete itself view WDestructiveClose PluginWindow * pluginWin = new PluginWindow(); pluginWin->show(); } void GlobalMenuBar::aboutWindowEvent() { AboutWin * win = new AboutWin(); win->show(); } void GlobalMenuBar::licenseWindowEvent() { LicenseWin * win = new LicenseWin(); win->show(); } void GlobalMenuBar::fillMruMenu() { m_mruMenu->clear(); for ( unsigned i = 0; i < g_prefs("mru").count(); i++ ) { m_mruMenu->addAction( QString::fromUtf8( g_prefs("mru")[i].stringValue().c_str() ) ); } } void GlobalMenuBar::openMru( QAction * id ) { ViewWindow::openModel( id->text().toUtf8() ); } void GlobalMenuBar::fillScriptMruMenuDisabled() { QAction *action; m_scriptMruMenu->clear(); for ( unsigned i = 0; i < g_prefs("script_mru").count(); i++ ) { action = m_scriptMruMenu->addAction( QString::fromUtf8( g_prefs("script_mru")[i].stringValue().c_str() ) ); action->setEnabled( false ); } } void GlobalMenuBar::dummyEvent() { } mm3d-master/src/implui/globalmenubar.h000066400000000000000000000032321324021725400202600ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2018 Zack Middleton * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __GLOBALMENUBAR_H #define __GLOBALMENUBAR_H #include "config.h" #include #include #include #include class GlobalMenuBar : public QObject { Q_OBJECT public: GlobalMenuBar(); ~GlobalMenuBar(); public slots: void openModelEvent(); void newModelEvent(); void quitEvent(); void pluginWindowEvent(); void helpWindowEvent(); void aboutWindowEvent(); void licenseWindowEvent(); void fillMruMenu(); void openMru( QAction * id ); void fillScriptMruMenuDisabled(); void dummyEvent(); protected: QMenuBar *m_menuBar; QMenu *m_fileMenu; QMenu *m_helpMenu; QMenu *m_mruMenu; QMenu *m_scriptMruMenu; }; #endif // __GLOBALMENUBAR_H mm3d-master/src/implui/groupclean.cc000066400000000000000000000043551324021725400177520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2009 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "groupclean.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include using std::list; using std::map; GroupCleanWin::GroupCleanWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setModal( true ); setupUi( this ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } GroupCleanWin::~GroupCleanWin() { } void GroupCleanWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_groupclean.html", true ); win->show(); } void GroupCleanWin::accept() { if ( m_mergeMaterials->isChecked() ) { m_model->mergeIdenticalMaterials(); } if ( m_removeMaterials->isChecked() ) { m_model->removeUnusedMaterials(); } if ( m_mergeGroups->isChecked() ) m_model->mergeIdenticalGroups(); { } if ( m_removeGroups->isChecked() ) { m_model->removeUnusedGroups(); } m_model->operationComplete( tr( "Group Clean-up", "operation complete" ).toUtf8() ); QDialog::accept(); } void GroupCleanWin::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/groupclean.h000066400000000000000000000024351324021725400176110ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2009 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __GROUPCLEAN_H #define __GROUPCLEAN_H #include "groupclean.base.h" #include class Model; class GroupCleanWin : public QDialog, public Ui::GroupCleanBase { Q_OBJECT public: GroupCleanWin( Model *, QWidget * parent = NULL ); virtual ~GroupCleanWin(); public slots: void accept(); void reject(); void helpNowEvent(); protected: Model * m_model; }; #endif // __GROUPCLEAN_H mm3d-master/src/implui/groupwin.cc000066400000000000000000000203341324021725400174600ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "groupwin.h" #include "model.h" #include "textureframe.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include #include #include #include #include #include #include GroupWindow::GroupWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); m_textureFrame->setModel( model ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); for ( int t = 0; t < m_model->getTextureCount(); t++ ) { m_textureComboBox->insertItem( t+1, QString::fromUtf8( m_model->getTextureName( t ) ) ); } for ( int t = 0; t < m_model->getGroupCount(); t++ ) { m_groupComboBox->insertItem( t+1, QString::fromUtf8( m_model->getGroupName( t ) ) ); } list triangles; m_model->getSelectedTriangles( triangles ); list::iterator it; for ( it = triangles.begin(); it != triangles.end(); it++ ) { int g = m_model->getTriangleGroup( *it ); if ( g >= 0 ) { m_groupComboBox->setCurrentIndex( g + 1 ); m_textureComboBox->setCurrentIndex( m_model->getGroupTextureId( g ) + 1 ); break; } } groupSelectedEvent( m_groupComboBox->currentIndex() ); updateTexture(); } GroupWindow::~GroupWindow() { } void GroupWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_groupwin.html", true ); win->show(); } void GroupWindow::newClickedEvent() { bool ok = true; bool valid = false; while ( !valid ) { QString groupName = QInputDialog::getText( this, tr("New group", "window title"), tr("Enter new group name:"), QLineEdit::Normal, QString::null, &ok ); if ( ok == true ) { if ( groupName.length() > 0 && groupName.length() < Model::MAX_GROUP_NAME_LEN ) { int groupNum = m_model->addGroup( groupName.toUtf8() ); m_groupComboBox->insertItem( groupNum + 1, groupName ); m_groupComboBox->setCurrentIndex( groupNum + 1 ); groupSelectedEvent( groupNum + 1 ); valid = true; } else { QString msg = tr( "Group name must be between 1 and %1 characters" ).arg( Model::MAX_GROUP_NAME_LEN - 1 ); QMessageBox::warning( this, tr("Bad group name", "window title"), msg, QMessageBox::Ok | QMessageBox::Default, 0, 0 ); } } else { valid = true; } } } void GroupWindow::renameClickedEvent() { bool ok = true; bool valid = false; int groupNum = m_groupComboBox->currentIndex(); if ( groupNum == 0 ) { QMessageBox::information( this, tr("Cannot change", "cannot change group name, window title"), tr("You cannot change the default group name"), QMessageBox::Ok | QMessageBox::Default, 0, 0 ); return; } groupNum--; while ( !valid ) { QString groupName = QInputDialog::getText( this, tr("New group", "window title"), tr("Enter new group name:"), QLineEdit::Normal, QString::fromUtf8( m_model->getGroupName( groupNum ) ), &ok ); if ( ok == true ) { if ( groupName.length() > 0 && groupName.length() < Model::MAX_GROUP_NAME_LEN ) { m_model->setGroupName( groupNum, groupName.toUtf8() ); m_groupComboBox->setItemText( groupNum + 1, groupName ); valid = true; } else { QString msg; msg.sprintf( "Group name must be between 1 and %d characters", Model::MAX_GROUP_NAME_LEN - 1 ); QMessageBox::warning( this, tr("Bad group name", "window title"), msg, QMessageBox::Ok | QMessageBox::Default, 0, 0 ); } } else { valid = true; } } } void GroupWindow::deleteClickedEvent() { int groupNum = m_groupComboBox->currentIndex(); m_groupComboBox->removeItem( groupNum ); m_model->deleteGroup( groupNum - 1 ); m_groupComboBox->setCurrentIndex( 0 ); groupSelectedEvent( 0 ); } void GroupWindow::selectFacesClickedEvent() { m_model->unselectAll(); m_model->selectGroup( m_groupComboBox->currentIndex() - 1 ); DecalManager::getInstance()->modelUpdated( m_model ); } void GroupWindow::unselectFacesClickedEvent() { m_model->unselectGroup( m_groupComboBox->currentIndex() - 1 ); DecalManager::getInstance()->modelUpdated( m_model ); } void GroupWindow::assignAsGroupClickedEvent() { m_model->setSelectedAsGroup( m_groupComboBox->currentIndex() - 1 ); DecalManager::getInstance()->modelAnimate( m_model ); } void GroupWindow::addToGroupClickedEvent() { m_model->addSelectedToGroup( m_groupComboBox->currentIndex() - 1 ); DecalManager::getInstance()->modelAnimate( m_model ); } void GroupWindow::smoothChangedEvent( int val ) { m_model->setGroupSmooth( m_groupComboBox->currentIndex() - 1, val ); QString text = tr( "Smoothness: " ); QString valStr; valStr.sprintf( "%03d", (int) ((val / 255.0) * 100.0 ) ); m_smoothLabel->setText( text + valStr ); m_model->calculateNormals(); DecalManager::getInstance()->modelUpdated( m_model ); } void GroupWindow::angleChangedEvent( int val ) { m_model->setGroupAngle( m_groupComboBox->currentIndex() - 1, val ); QString text = tr( "Max Angle: " ); QString valStr; valStr.sprintf( "%03d", val ); m_angleLabel->setText( text + valStr ); m_model->calculateNormals(); DecalManager::getInstance()->modelUpdated( m_model ); } void GroupWindow::groupSelectedEvent( int id ) { if ( id > 0 ) { m_smoothSlider->setEnabled( true ); m_smoothSlider->setValue( m_model->getGroupSmooth( id - 1 ) ); m_angleSlider->setEnabled( true ); m_angleSlider->setValue( m_model->getGroupAngle( id - 1 ) ); m_renameButton->setEnabled( true ); m_deleteButton->setEnabled( true ); m_assignAsGroupButton->setEnabled( true ); m_addToGroupButton->setEnabled( true ); m_textureComboBox->setEnabled( true ); int texId = m_model->getGroupTextureId( id - 1 ); m_textureComboBox->setCurrentIndex( texId + 1 ); updateTexture(); } else { m_smoothSlider->setEnabled( false ); m_angleSlider->setEnabled( false ); m_renameButton->setEnabled( false ); m_deleteButton->setEnabled( false ); m_assignAsGroupButton->setEnabled( false ); m_addToGroupButton->setEnabled( false ); m_textureComboBox->setEnabled( false ); } DecalManager::getInstance()->modelAnimate( m_model ); } void GroupWindow::textureSelectedEvent( int id ) { int groupId = m_groupComboBox->currentIndex() - 1; if ( groupId >= 0 ) { m_model->setGroupTextureId( groupId, id - 1 ); } updateTexture(); DecalManager::getInstance()->modelAnimate( m_model ); } void GroupWindow::updateTexture() { m_textureFrame->textureChangedEvent( m_textureComboBox->currentIndex() ); } void GroupWindow::accept() { m_model->operationComplete( tr( "Group changes", "operation complete" ).toUtf8() ); QDialog::accept(); DecalManager::getInstance()->modelUpdated( m_model ); } void GroupWindow::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/groupwin.h000066400000000000000000000033041324021725400173200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __GROUPWIN_H #define __GROUPWIN_H #include "groupwin.base.h" #include class Model; class GroupWindow : public QDialog, public Ui::GroupWinBase { Q_OBJECT public: GroupWindow( Model * model, QWidget * parent = NULL ); virtual ~GroupWindow(); public slots: void helpNowEvent(); void newClickedEvent(); void renameClickedEvent(); void deleteClickedEvent(); void selectFacesClickedEvent(); void unselectFacesClickedEvent(); void assignAsGroupClickedEvent(); void addToGroupClickedEvent(); void smoothChangedEvent(int); void angleChangedEvent(int); void groupSelectedEvent(int); void textureSelectedEvent(int); void accept(); void reject(); protected: void updateTexture(); Model * m_model; }; #endif // __GROUPWIN_H mm3d-master/src/implui/helpwin.cc000066400000000000000000000036261324021725400172610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "helpwin.h" #include "sysconf.h" #include #include HelpWin::HelpWin( const char * document, bool modal, QWidget * parent ) : QDialog( parent ) { setAttribute( Qt::WA_DeleteOnClose ); setModal( modal ); setupUi( this ); #ifdef WIN32 QString source = QString( getDocDirectory().c_str() ) + QString( "\\olh_index.html" ); #else QString source = QString( getDocDirectory().c_str() ) + QString( "/olh_index.html" ); #endif m_text->setSource( QUrl::fromLocalFile( source ) ); if ( document ) { #ifdef WIN32 QString source = QString( getDocDirectory().c_str() ) + QString( "\\" ) + QString( document ); #else QString source = QString( getDocDirectory().c_str() ) + QString( "/" ) + QString( document ); #endif m_text->setSource( QUrl::fromLocalFile( source ) ); } //m_text->home(); m_forwardButton->setEnabled( false ); m_backButton->setEnabled( false ); } HelpWin::~HelpWin() { } mm3d-master/src/implui/helpwin.h000066400000000000000000000022701324021725400171150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __HELPWIN_H #define __HELPWIN_H #include "helpwin.base.h" #include class HelpWin : public QDialog, public Ui::HelpWinBase { Q_OBJECT public: HelpWin( const char * document = "olh_index.html", bool modal = false, QWidget * parent = NULL ); virtual ~HelpWin(); protected: }; #endif // __HELPWIN_H mm3d-master/src/implui/jointwin.cc000066400000000000000000000147011324021725400174500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "jointwin.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include #include using std::list; #include "model.h" #include "decalmgr.h" #include "log.h" #include "msg.h" #include "modelstatus.h" JointWin::JointWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); for ( int t = 0; t < m_model->getBoneJointCount(); t++ ) { m_jointName->insertItem( t, QString::fromUtf8( m_model->getBoneJointName(t) ) ); } list joints; m_model->getSelectedBoneJoints( joints ); if ( ! joints.empty() ) { m_jointName->setCurrentIndex( joints.front() ); jointNameSelected( joints.front() ); } else { m_jointName->setCurrentIndex( 0 ); jointNameSelected( 0 ); } } JointWin::~JointWin() { } void JointWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_jointwin.html", true ); win->show(); } void JointWin::jointNameSelected( int index ) { if ( index < m_jointName->count() ) { m_model->unselectAllBoneJoints(); m_model->selectBoneJoint( index ); m_deleteButton->setEnabled( true ); m_renameButton->setEnabled( true ); m_selectVerticesButton->setEnabled( true ); m_assignVerticesButton->setEnabled( true ); DecalManager::getInstance()->modelUpdated( m_model ); } else { m_deleteButton->setEnabled( false ); m_renameButton->setEnabled( false ); m_selectVerticesButton->setEnabled( false ); m_assignVerticesButton->setEnabled( false ); } } void JointWin::deleteClicked() { if ( m_jointName->count() ) { m_model->deleteBoneJoint( m_jointName->currentIndex() ); } } void JointWin::renameClicked() { if ( m_jointName->count() ) { bool ok = false; int jointNum = m_jointName->currentIndex(); QString jointName = QInputDialog::getText( this, tr("Rename joint", "window title"), tr("Enter new joint name:"), QLineEdit::Normal, QString::fromUtf8( m_model->getBoneJointName( jointNum ) ), &ok ); if ( ok ) { m_model->setBoneJointName( jointNum, jointName.toUtf8() ); m_jointName->setItemText( jointNum, jointName ); } } } void JointWin::selectVerticesClicked() { if ( m_jointName->count() ) { int joint = m_jointName->currentIndex(); m_model->unselectAllVertices(); unsigned vcount = m_model->getVertexCount(); for ( unsigned v = 0; v < vcount; v++ ) { Model::InfluenceList l; m_model->getVertexInfluences( v, l ); Model::InfluenceList::iterator it; for ( it = l.begin(); it != l.end(); it++ ) { if ( (*it).m_boneId == joint ) { m_model->selectVertex( v ); break; } } } unsigned pcount = m_model->getPointCount(); for ( unsigned p = 0; p < pcount; p++ ) { Model::InfluenceList l; m_model->getPointInfluences( p, l ); Model::InfluenceList::iterator it; for ( it = l.begin(); it != l.end(); it++ ) { if ( (*it).m_boneId == joint ) { m_model->selectPoint( p ); break; } } } DecalManager::getInstance()->modelUpdated( m_model ); } } void JointWin::selectUnassignedClicked() { m_model->unselectAllVertices(); unsigned vcount = m_model->getVertexCount(); for ( unsigned v = 0; v < vcount; v++ ) { Model::InfluenceList l; m_model->getVertexInfluences( v, l ); if ( l.empty() ) { m_model->selectVertex( v ); } } unsigned pcount = m_model->getPointCount(); for ( unsigned p = 0; p < pcount; p++ ) { Model::InfluenceList l; m_model->getPointInfluences( p, l ); if ( l.empty() ) { m_model->selectPoint( p ); } } DecalManager::getInstance()->modelUpdated( m_model ); } void JointWin::assignVerticesClicked() { log_debug( "assignVerticesClicked()\n" ); if ( m_jointName->count() ) { unsigned joint = m_jointName->currentIndex(); list posList; m_model->getSelectedPositions( posList ); list::iterator it; log_debug( "assigning %d objects to joint %d\n", posList.size(), joint ); for ( it = posList.begin(); it != posList.end(); it++ ) { m_model->setPositionBoneJoint( *it, joint ); } } } void JointWin::addVerticesClicked() { log_debug( "addVerticesClicked()\n" ); if ( m_jointName->count() ) { unsigned joint = m_jointName->currentIndex(); list posList; m_model->getSelectedPositions( posList ); list::iterator it; log_debug( "adding %d objects to joint %d\n", posList.size(), joint ); for ( it = posList.begin(); it != posList.end(); it++ ) { m_model->addPositionInfluence( *it, joint, Model::IT_Custom, 1.0 ); } } } void JointWin::accept() { log_debug( "Joint changes complete\n" ); m_model->operationComplete( tr( "Joint changes", "operation complete" ).toUtf8() ); QDialog::accept(); } void JointWin::reject() { log_debug( "Joint changes canceled\n" ); m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/jointwin.h000066400000000000000000000030271324021725400173110ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __JOINTWIN_H #define __JOINTWIN_H #include "jointwin.base.h" #include class Model; class JointWin : public QDialog, public Ui::JointWinBase { Q_OBJECT public: JointWin( Model * model, QWidget * parent = NULL ); virtual ~JointWin(); public slots: void helpNowEvent(); void deleteClicked(); void renameClicked(); void selectVerticesClicked(); void selectUnassignedClicked(); void assignVerticesClicked(); void addVerticesClicked(); void jointNameSelected( int index ); protected slots: void accept(); void reject(); protected: Model * m_model; }; #endif // __JOINTWIN_H mm3d-master/src/implui/keycfg.cc000066400000000000000000000464761324021725400170750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include #include "keycfg.h" #include "log.h" #include "qtmain.h" #include static void _chomp( char * str ) { int len = 0; len = strlen( str ) - 1; while ( len >= 0 && isspace( str[len] ) ) { str[len] = '\0'; len--; } } static void _writeDefaultFile( const char * filename ) { FILE * fp = fopen( filename, "w" ); if ( fp ) { fprintf( fp, "; This file is used to change key bindings for Misfit Model 3D.\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; To change keyboard shortcuts, add keyboard shortcuts assignments at the bottom \n" ); fprintf( fp, "; of this file. The format for keyboard shortcuts is:\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; mm3d_command_name MODIFIER+Key\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; For a full list of MM3D command names, see keycfg.out. The keycfg.out file\n" ); fprintf( fp, "; is written at the end of every MM3D session and includes all the currently\n" ); fprintf( fp, "; assigned shortcuts (including default values and user-specified values).\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; There can be as many spaces between the command name and the keyboard shortcut\n" ); fprintf( fp, "; as you want, but there cannot be any spaces in the keyboard shortcut sequence.\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Valid modifiers are:\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Ctrl\n" ); fprintf( fp, "; Alt\n" ); fprintf( fp, "; Shift\n" ); fprintf( fp, "; Meta\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Modifiers are not case-sensitive. You can have as many modifiers as you want \n" ); fprintf( fp, "; (none, all, or any combination).\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Most keys can be entered by typing the actual key (letters, numbers, arithmatic\n" ); fprintf( fp, "; operators, etc).\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Some special keys:\n" ); fprintf( fp, ";\n" ); fprintf( fp, "; Del\n" ); fprintf( fp, "; PgDown\n" ); fprintf( fp, "; PgUp\n" ); fprintf( fp, "; Space\n" ); fprintf( fp, "; Print (Print Screen key)\n" ); fprintf( fp, "; Up\n" ); fprintf( fp, "; Down\n" ); fprintf( fp, "; Left\n" ); fprintf( fp, "; Right\n" ); fprintf( fp, "; Esc\n" ); fprintf( fp, "; Tab\n" ); fprintf( fp, "; Enter\n" ); fprintf( fp, "; Return\n" ); fprintf( fp, "; Backspace\n" ); fprintf( fp, "; Insert\n" ); fprintf( fp, "; Ins\n" ); fprintf( fp, "; Delete\n" ); fprintf( fp, "; Del\n" ); fprintf( fp, "; Home\n" ); fprintf( fp, "; End\n" ); fprintf( fp, "; F1 through F12\n" ); fprintf( fp, ";\n" ); fprintf( fp, "\n" ); fprintf( fp, "; Uncomment the following line to assign Shift+F1 to the Help->Contents menu item\n" ); fprintf( fp, ";viewwin_help_contents Shift+F1\n" ); fprintf( fp, "\n" ); fprintf( fp, "; Uncomment the following line to remove the keyboard shortcut for File->Save\n" ); fprintf( fp, ";viewwin_file_save \n" ); fclose( fp ); } } KeyConfig g_keyConfig; KeyConfig::KeyConfig() { } KeyConfig::~KeyConfig() { } QKeySequence KeyConfig::getKey( const char * operation ) { KeyDataList::iterator it; for ( it = m_list.begin(); it != m_list.end(); it++ ) { if ( strcasecmp( operation, (*it).operation.c_str() ) == 0 ) { return (*it).key; } } KeyDataT kd; kd.operation = operation; m_list.push_back( kd ); return m_list.back().key; } void KeyConfig::setKey( const char * operation, const QKeySequence & key ) { KeyDataList::iterator it; // Clear any operation key that uses this key (to prevent duplicates) if ( !key.isEmpty() ) { for ( it = m_list.begin(); it != m_list.end(); it++ ) { if ( (*it).key == key ) { (*it).key = 0; } } } for ( it = m_list.begin(); it != m_list.end(); it++ ) { if ( strcasecmp( operation, (*it).operation.c_str() ) == 0 ) { (*it).key = key; return; } } KeyDataT kd; kd.operation = operation; kd.key = key; m_list.push_back( kd ); } void KeyConfig::setDefaultKey( const char * operation, const QKeySequence & key ) { KeyDataList::iterator it; // See if this key is already in use (and ignore this request) for ( it = m_list.begin(); it != m_list.end(); it++ ) { if ( (*it).key == key ) { return; } } // See if this action is already defined (and ignore this request) for ( it = m_list.begin(); it != m_list.end(); it++ ) { if ( strcasecmp( operation, (*it).operation.c_str() ) == 0 ) { return; } } // Key combo not in use, action not already defined, save default KeyDataT kd; kd.operation = operation; kd.key = key; m_list.push_back( kd ); } bool KeyConfig::saveFile( const char * filename ) { FILE * fp = fopen( filename, "w" ); if ( fp ) { KeyDataList::iterator it; for ( it = m_list.begin(); it != m_list.end(); it++ ) { QString keyStr = (*it).key.toString(); if ( keyStr.isNull() ) { fprintf( fp, "%s \n", (*it).operation.c_str() ); } else { fprintf( fp, "%s %s\n", (*it).operation.c_str(), (const char *) keyStr.toUtf8() ); } } fclose( fp ); return true; } else { log_error( "Could write to key config file: %s\n", filename ); } return false; } bool KeyConfig::loadFile( const char * filename ) { log_debug( "loading keyboard shortcut config file:\n" ); log_debug( " %s\n", filename ); FILE * fp = fopen( filename, "r" ); if ( fp ) { log_debug( "reading file...\n" ); m_list.clear(); char line[1024]; while ( fgets( line, sizeof(line), fp ) ) { _chomp( line ); if ( isspace(line[0]) || line[0] == ';' || line[0] == '#' || strncmp(line, "//", 2 ) == 0 ) { // comment, ignore it } else if ( line[0] ) { // not blank or comment line, parse it char * space = strchr( line, ' ' ); if ( space ) { std::string op; op.assign( line, space - line ); char * str = space; QKeySequence key; if ( op.size() > 0 ) { while ( isspace( str[0] ) ) { str++; } // empty definitions are valid QString s( str ); QKeySequence k( s ); setKey( op.c_str(), k ); } } else { std::string op = line; if ( op.size() > 0 ) { QKeySequence k; setKey( op.c_str(), k ); } } } } fclose( fp ); return true; } else { log_debug( "keyboard config file does not exist, creating...\n" ); _writeDefaultFile( filename ); } return false; } /* int KeyConfig::getSpecialKey( const char * keyName ) { for ( unsigned int k = 0; k < KEY_NAMES; k++ ) { if ( strcasecmp( keyName, _special[k].operation.c_str() ) == 0 ) { return _special[k].key; } } return 0; } */ /* std::string KeyConfig::getSpecialKeyName( int key ) { for ( unsigned int k = 0; k < KEY_NAMES; k++ ) { if ( key == _special[k].key ) { return _special[k].operation; } } return ""; } */ bool keycfg_load_file( const char * filename ) { return g_keyConfig.loadFile( filename ); } bool keycfg_save_file( const char * filename ) { return g_keyConfig.saveFile( filename ); } void keycfg_set_defaults() { QApplication * a = ui_getapp(); // Tools g_keyConfig.setDefaultKey( "tool_snap_to_grid", 0 ); g_keyConfig.setDefaultKey( "tool_snap_to_vertex", 0 ); g_keyConfig.setDefaultKey( "tool_select_vertices", QKeySequence( a->translate( "KeyConfig", "V", "Select Vertices Tool Shortcut" )) ); g_keyConfig.setDefaultKey( "tool_select_faces", QKeySequence( a->translate( "KeyConfig", "F", "Select Faces Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_select_connected_mesh", QKeySequence( a->translate( "KeyConfig", "C", "Select Connected Mesh Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_select_groups", QKeySequence( a->translate( "KeyConfig", "G", "Select Groups Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_select_bone_joints", QKeySequence( a->translate( "KeyConfig", "B", "Select Bone Joints Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_select_points", QKeySequence( a->translate( "KeyConfig", "T", "Select Points Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_select_projections", 0 ); g_keyConfig.setDefaultKey( "tool_move", QKeySequence( a->translate( "KeyConfig", "M", "Move Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_rotate", QKeySequence( a->translate( "KeyConfig", "R", "Rotate Tool Shortcut")) ); g_keyConfig.setDefaultKey( "tool_scale", 0 ); g_keyConfig.setDefaultKey( "tool_shear", 0 ); g_keyConfig.setDefaultKey( "tool_attract_near", 0 ); g_keyConfig.setDefaultKey( "tool_attract_far", 0 ); g_keyConfig.setDefaultKey( "tool_move_background_image", 0 ); g_keyConfig.setDefaultKey( "tool_scale_background_image", 0 ); g_keyConfig.setDefaultKey( "tool_create_vertex", 0 ); g_keyConfig.setDefaultKey( "tool_create_rectangle", 0 ); g_keyConfig.setDefaultKey( "tool_create_cube", 0 ); g_keyConfig.setDefaultKey( "tool_create_ellipsoid", 0 ); g_keyConfig.setDefaultKey( "tool_create_cylinder", 0 ); g_keyConfig.setDefaultKey( "tool_create_torus", 0 ); g_keyConfig.setDefaultKey( "tool_create_polygon", 0 ); g_keyConfig.setDefaultKey( "tool_create_bone_joint", 0 ); g_keyConfig.setDefaultKey( "tool_create_point", 0 ); g_keyConfig.setDefaultKey( "tool_create_projection", 0 ); // Commands g_keyConfig.setDefaultKey( "cmd_invert_selection", 0 ); g_keyConfig.setDefaultKey( "cmd_select_free_vertices", 0 ); g_keyConfig.setDefaultKey( "cmd_hide_hide_unselected", QKeySequence( a->translate( "KeyConfig", "H", "Hide Unselected Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_hide_hide_selected", QKeySequence( a->translate( "KeyConfig", "Shift+H", "Hide Selected Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_hide_unhide_all", QKeySequence( a->translate( "KeyConfig", "Shift+U", "Unhide All Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_hide", 0 ); g_keyConfig.setDefaultKey( "cmd_delete", QKeySequence( a->translate( "KeyConfig", "Delete", "Delete Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_duplicate", QKeySequence( a->translate( "KeyConfig", "Ctrl+D", "Duplicate Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_copy_selected_to_clipboard", QKeySequence( a->translate( "KeyConfig", "Ctrl+C", "Copy to Clipboard Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_paste_from_clipboard", QKeySequence( a->translate( "KeyConfig", "Ctrl+V", "Paste from Clipboard Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_flip_flip_x", 0 ); g_keyConfig.setDefaultKey( "cmd_flip_flip_y", 0 ); g_keyConfig.setDefaultKey( "cmd_flip_flip_z", 0 ); g_keyConfig.setDefaultKey( "cmd_flip", 0 ); g_keyConfig.setDefaultKey( "cmd_flatten_flatten_x", 0 ); g_keyConfig.setDefaultKey( "cmd_flatten_flatten_y", 0 ); g_keyConfig.setDefaultKey( "cmd_flatten_flatten_z", 0 ); g_keyConfig.setDefaultKey( "cmd_flatten", 0 ); g_keyConfig.setDefaultKey( "cmd_extrude", QKeySequence( a->translate( "KeyConfig", "Insert", "Extrude Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_invert_normals", 0 ); g_keyConfig.setDefaultKey( "cmd_weld_vertices", QKeySequence( a->translate( "KeyConfig", "Ctrl+W", "Weld Command Shortcut")) ); g_keyConfig.setDefaultKey( "cmd_unweld_vertices", 0 ); g_keyConfig.setDefaultKey( "cmd_snap_vertices_together_snap_all_selected", 0 ); g_keyConfig.setDefaultKey( "cmd_snap_vertices_together_snap_nearest_selected", 0 ); g_keyConfig.setDefaultKey( "cmd_snap_vertices_together_snap_all_and_weld", 0 ); g_keyConfig.setDefaultKey( "cmd_snap_vertices_together_snap_nearest_and_weld", 0 ); g_keyConfig.setDefaultKey( "cmd_snap_vertices_together", 0 ); g_keyConfig.setDefaultKey( "cmd_edge_turn", 0 ); g_keyConfig.setDefaultKey( "cmd_edge_divide", 0 ); g_keyConfig.setDefaultKey( "cmd_subdivide_faces", 0 ); g_keyConfig.setDefaultKey( "cmd_make_face_from_vertices", 0 ); g_keyConfig.setDefaultKey( "cmd_cap_holes", 0 ); g_keyConfig.setDefaultKey( "cmd_rotate_texture_coordinates_face", 0 ); g_keyConfig.setDefaultKey( "cmd_rotate_texture_coordinates_group", 0 ); g_keyConfig.setDefaultKey( "cmd_rotate_texture_coordinates", 0 ); g_keyConfig.setDefaultKey( "cmd_align_selected", 0 ); g_keyConfig.setDefaultKey( "cmd_spherify", 0 ); g_keyConfig.setDefaultKey( "cmd_simplify_mesh", 0 ); g_keyConfig.setDefaultKey( "cmd_points", 0 ); // View Window g_keyConfig.setDefaultKey( "viewwin_file_new", QKeySequence( a->translate( "KeyConfig", "Ctrl+N", "File | New Window Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_file_open", QKeySequence( a->translate( "KeyConfig", "Ctrl+O", "File | Open Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_file_save", QKeySequence( a->translate( "KeyConfig", "Ctrl+S", "File | Save Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_file_save_as", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_set_background_image", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_run_script", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_merge", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_merge_animations", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_plugins", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_close", 0 ); g_keyConfig.setDefaultKey( "viewwin_file_quit", QKeySequence( a->translate( "KeyConfig", "Ctrl+Q", "File | Quit Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_view_render_joints_hide", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_joints_lines", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_joints_bones", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_badtex_red", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_badtex_blank", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_3d_lines_show", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_3d_lines_hide", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_backface_show", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_render_backface_hide", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_frame_all", QKeySequence( a->translate( "KeyConfig", "Home", "View | Frame All Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_view_frame_selected", QKeySequence( a->translate( "KeyConfig", "Shift+Home", "View | Frame Selected Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_view_show_properties", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3d_wireframe", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3d_flat", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3d_smooth", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3d_textured", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3d_alpha", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_ortho_wireframe", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_ortho_flat", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_ortho_smooth", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_ortho_textured", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_ortho_alpha", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_1", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_1x2", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_2x1", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_2x2", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_2x3", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3x2", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_3x3", 0 ); g_keyConfig.setDefaultKey( "viewwin_view_viewport_settings", 0 ); g_keyConfig.setDefaultKey( "viewwin_groups_edit_groups", QKeySequence( a->translate( "KeyConfig", "Ctrl+G", "Groups | Edit Groups Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_groups_edit_materials", QKeySequence( a->translate( "KeyConfig", "Ctrl+M", "Groups | Edit Materials Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_groups_edit_texture_coordinates", QKeySequence( a->translate( "KeyConfig", "Ctrl+E", "Groups | Edit Texture Coordinates Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_groups_paint_texture", 0 ); g_keyConfig.setDefaultKey( "viewwin_groups_edit_projection", 0 ); g_keyConfig.setDefaultKey( "viewwin_groups_edit_meta_data", 0 ); g_keyConfig.setDefaultKey( "viewwin_groups_boolean_operation", 0 ); g_keyConfig.setDefaultKey( "viewwin_groups_reload_textures", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_edit_joints", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_assign_selected", QKeySequence( a->translate( "KeyConfig", "Ctrl+B", "Joints | Assign Selected Shortcut")) ); g_keyConfig.setDefaultKey( "viewwin_joints_remove_influences", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_remove_joint", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_select_joint_influences", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_select_influenced_vertices", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_select_influenced_points", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_select_unassigned_vertices", 0 ); g_keyConfig.setDefaultKey( "viewwin_joints_select_unassigned_points", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_start_mode", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_stop_mode", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_animation_sets", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_export", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_frame_copy", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_frame_paste", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_frame_clear", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_set_rotation", 0 ); g_keyConfig.setDefaultKey( "viewwin_anim_set_translation", 0 ); g_keyConfig.setDefaultKey( "viewwin_help_contents", 0 ); g_keyConfig.setDefaultKey( "viewwin_help_license", 0 ); g_keyConfig.setDefaultKey( "viewwin_help_about", 0 ); } mm3d-master/src/implui/keycfg.h000066400000000000000000000035121324021725400167170ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __KEYCFG_H #define __KEYCFG_H #include #include #include class KeyConfig { public: KeyConfig(); virtual ~KeyConfig(); QKeySequence getKey( const char * operation ); void setKey( const char * operation, const QKeySequence & key ); void setDefaultKey( const char * operation, const QKeySequence & key ); bool saveFile( const char * filename ); bool loadFile( const char * filename ); //static int getSpecialKey( const char * keyName ); //static std::string getSpecialKeyName( int key ); struct _KeyData_t { std::string operation; QKeySequence key; }; typedef struct _KeyData_t KeyDataT; typedef std::list< KeyDataT > KeyDataList; protected: KeyDataList m_list; }; extern KeyConfig g_keyConfig; bool keycfg_load_file( const char * filename ); bool keycfg_save_file( const char * filename ); void keycfg_set_defaults(); #endif // __KEYCFG_H mm3d-master/src/implui/keyvaluewin.cc000066400000000000000000000031321324021725400201460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "keyvaluewin.h" #include "model.h" #include "glmath.h" #include #include #include #include #include #include #include KeyValueWindow::KeyValueWindow( QTreeWidgetItem * item, QWidget * parent ) : QDialog( parent ), m_item( item ) { setupUi( this ); setModal( true ); m_nameEdit->setText( item->text(0) ); m_valueEdit->setText( item->text(1) ); } KeyValueWindow::~KeyValueWindow() { } void KeyValueWindow::accept() { m_item->setText( 0, m_nameEdit->text() ); m_item->setText( 1, m_valueEdit->text() ); QDialog::accept(); } void KeyValueWindow::reject() { QDialog::reject(); } mm3d-master/src/implui/keyvaluewin.h000066400000000000000000000024661324021725400200210ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __KEYVALUEWIN_H #define __KEYVALUEWIN_H #include "keyvaluewin.base.h" #include class QTreeWidgetItem; class KeyValueWindow : public QDialog, public Ui::KeyValueWindowBase { Q_OBJECT public: KeyValueWindow( QTreeWidgetItem * item, QWidget * parent = NULL ); virtual ~KeyValueWindow(); public slots: void accept(); void reject(); protected: QTreeWidgetItem * m_item; }; #endif // __KEYVALUEWIN_H mm3d-master/src/implui/licensewin.cc000066400000000000000000000027311324021725400177470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "licensewin.h" #include "sysconf.h" #include LicenseWin::LicenseWin( QWidget * parent ) : QDialog( parent ) { setAttribute( Qt::WA_DeleteOnClose ); setModal( false ); setupUi( this ); resize( 600, 400 ); setWindowTitle( tr("GNU General Public License") ); #ifdef WIN32 QString source = QString( getDocDirectory().c_str() ) + QString( "/olh_license.html" ); #else QString source = QString( getDocDirectory().c_str() ) + QString( "/olh_license.html" ); #endif m_text->setSource( QUrl::fromLocalFile( source ) ); } LicenseWin::~LicenseWin() { } mm3d-master/src/implui/licensewin.h000066400000000000000000000022151324021725400176060ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __LICENSEWIN_H #define __LICENSEWIN_H #include "textwin.base.h" #include class LicenseWin : public QDialog, public Ui::TextWinBase { Q_OBJECT public: LicenseWin( QWidget * parent = NULL ); virtual ~LicenseWin(); protected: }; #endif // __LICENSEWIN_H mm3d-master/src/implui/mapdirection.cc000066400000000000000000000024311324021725400202620ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "mapdirection.h" #include MapDirection::MapDirection( QWidget * parent ) : QDialog( parent ) { setupUi( this ); setModal( true ); m_directionComboBox->setCurrentIndex( 0 ); } MapDirection::~MapDirection() { } int MapDirection::getMapDirection() { return m_directionComboBox->currentIndex(); } void MapDirection::setMapDirection( int index ) { m_directionComboBox->setCurrentIndex( index ); } mm3d-master/src/implui/mapdirection.h000066400000000000000000000023261324021725400201270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MAPDIRECTION_H #define __MAPDIRECTION_H #include "mapdirection.base.h" #include class MapDirection : public QDialog, public Ui::MapDirectionBase { public: MapDirection( QWidget * parent = NULL ); virtual ~MapDirection(); void setMapDirection( int ); int getMapDirection(); protected: }; #endif // __MAPDIRECTION_H mm3d-master/src/implui/mergewin.cc000066400000000000000000000046411324021725400174260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "mergewin.h" #include "model.h" #include "glmath.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include #include #include #include MergeWindow::MergeWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } MergeWindow::~MergeWindow() { } void MergeWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_mergewin.html", true ); win->show(); } void MergeWindow::getRotation( double * vec ) { if ( vec ) { vec[0] = m_rotX->text().toDouble() * PIOVER180; vec[1] = m_rotY->text().toDouble() * PIOVER180; vec[2] = m_rotZ->text().toDouble() * PIOVER180; } } void MergeWindow::getTranslation( double * vec ) { if ( vec ) { vec[0] = m_transX->text().toDouble(); vec[1] = m_transY->text().toDouble(); vec[2] = m_transZ->text().toDouble(); } } void MergeWindow::includeAnimEvent( bool o ) { m_animMerge->setEnabled( o ); m_animAppend->setEnabled( o ); } void MergeWindow::accept() { m_model->operationComplete( tr( "Merge models", "operation complete" ).toUtf8() ); QDialog::accept(); } void MergeWindow::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/mergewin.h000066400000000000000000000032061324021725400172640ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MERGEWIN_H #define __MERGEWIN_H #include "mergewin.base.h" #include class Model; class MergeWindow : public QDialog, public Ui::MergeWinBase { Q_OBJECT public: MergeWindow( Model *, QWidget * parent = NULL ); virtual ~MergeWindow(); void getRotation( double * vec ); void getTranslation( double * vec ); bool getIncludeTexture() { return m_textureInclude->isChecked(); }; bool getIncludeAnimation() { return m_animInclude->isChecked(); }; bool getAnimationMerge() { return m_animInclude->isChecked() && m_animMerge->isChecked(); }; public slots: void helpNowEvent(); void includeAnimEvent( bool o ); void accept(); void reject(); protected: Model * m_model; }; #endif // __MERGEWIN_H mm3d-master/src/implui/metawin.cc000066400000000000000000000064701324021725400172570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "metawin.h" #include "model.h" #include "keyvaluewin.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include #include #include #include #include MetaWindow::MetaWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); m_list->header()->setSectionsClickable( false ); m_list->header()->setSectionsMovable( false ); unsigned count = m_model->getMetaDataCount(); for ( unsigned int m = 0; m < count; m++ ) { char key[1024]; char value[1024]; m_model->getMetaData( m, key, sizeof(key), value, sizeof(value) ); QTreeWidgetItem * item = new QTreeWidgetItem( m_list ); item->setText( 0, QString::fromUtf8( key ) ); item->setText( 1, QString::fromUtf8( value ) ); } QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } MetaWindow::~MetaWindow() { } void MetaWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_metawin.html", true ); win->show(); } void MetaWindow::newClicked() { QTreeWidgetItem * item = new QTreeWidgetItem( m_list ); item->setText( 0, tr("Name", "meta value key name") ); item->setText( 1, tr("Value", "meta value 'value'") ); int count = m_list->topLevelItemCount(); for ( int i = 0; i < count; ++i ) { m_list->topLevelItem( i )->setSelected( false ); } item->setSelected( true ); m_list->setCurrentItem( item ); } void MetaWindow::deleteClicked() { delete m_list->currentItem(); } void MetaWindow::editItemEvent( QTreeWidgetItem * item, int col ) { KeyValueWindow w( item ); w.exec(); } void MetaWindow::accept() { m_model->clearMetaData(); int count = m_list->topLevelItemCount(); for ( int i = 0; i < count; ++i ) { QTreeWidgetItem * item = m_list->topLevelItem(i); m_model->addMetaData( (const char *) item->text(0).toUtf8(), (const char *) item->text(1).toUtf8() ); } m_model->operationComplete( tr( "Change meta data", "operation complete" ).toUtf8() ); QDialog::accept(); } void MetaWindow::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/metawin.h000066400000000000000000000026311324021725400171140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __METAWIN_H #define __METAWIN_H #include "metawin.base.h" #include class Model; class QTreeWidgetItem; class MetaWindow : public QDialog, public Ui::MetaWindowBase { Q_OBJECT public: MetaWindow( Model *, QWidget * parent = NULL ); virtual ~MetaWindow(); public slots: void helpNowEvent(); void newClicked(); void deleteClicked(); void editItemEvent( QTreeWidgetItem * item, int col ); void accept(); void reject(); protected: Model * m_model; }; #endif // __METAWIN_H mm3d-master/src/implui/ms3dprompt.cc000066400000000000000000000067241324021725400177250ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "ms3dprompt.h" #include "ms3dfilter.h" #include "model.h" #include "mm3dport.h" #include "helpwin.h" #include #include #include Ms3dPrompt::Ms3dPrompt() : QDialog( NULL ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } Ms3dPrompt::~Ms3dPrompt() { } void Ms3dPrompt::setOptions( Ms3dFilter::Ms3dOptions * opts ) { switch ( opts->m_subVersion ) { case 0: default: m_subVersion0->setChecked( true ); break; case 1: m_subVersion1->setChecked( true ); break; case 2: m_subVersion2->setChecked( true ); break; } char str[20]; PORT_snprintf( str, sizeof(str), "%X", opts->m_vertexExtra ); m_vertexExtra->setText( str ); // TODO joint color //PORT_snprintf( str, sizeof(str), "%X", opts->m_jointColor ); //m_jointColor->setText( str ); updateExtraEnabled(); } void Ms3dPrompt::getOptions( Ms3dFilter::Ms3dOptions * opts ) { opts->m_subVersion = 0; if ( m_subVersion1->isChecked() ) opts->m_subVersion = 1; if ( m_subVersion2->isChecked() ) opts->m_subVersion = 2; uint32_t val = 0xffffffff; sscanf( m_vertexExtra->text().toUtf8(), "%X", &val); opts->m_vertexExtra = val; // TODO joint color //val = 0xffffffff; //sscanf( m_jointColor->text().toUtf8(), "%X", &val); //opts->m_vertexExtra = val; } void Ms3dPrompt::helpNowEvent() { HelpWin * win = new HelpWin( "olh_ms3dprompt.html", true ); win->show(); } void Ms3dPrompt::subVersionChangedEvent() { updateExtraEnabled(); } void Ms3dPrompt::updateExtraEnabled() { m_vertexExtra->setEnabled( m_subVersion2->isChecked() ); // TODO joint color //m_jointColor->setEnabled( !m_subVersion0->isChecked() ); } // This function takes a ModelFilter::Options argument, downcasts it // to an Ms3dOptions object, and uses it to prompt the user for // options for the MS3D file filter. // // This function is registered with the Ms3dFilter class when the // filter is created in stdfilters.cc. bool ms3dprompt_show( Model * model, ModelFilter::Options * o ) { bool rval = false; Ms3dPrompt p; Ms3dFilter::Ms3dOptions * opts = dynamic_cast< Ms3dFilter::Ms3dOptions * >( o ); if ( opts ) { opts->setOptionsFromModel( model ); p.setOptions( opts ); if ( p.exec() ) { rval = true; p.getOptions( opts ); } } else { rval = true; } return rval; } mm3d-master/src/implui/ms3dprompt.h000066400000000000000000000027351324021725400175650ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MS3DPROMPT_H #define __MS3DPROMPT_H #include "ms3dprompt.base.h" #include "modelfilter.h" #include "ms3dfilter.h" #include class Model; class Ms3dPrompt : public QDialog, public Ui::Ms3dPromptBase { Q_OBJECT public: Ms3dPrompt(); virtual ~Ms3dPrompt(); void setOptions( Ms3dFilter::Ms3dOptions * o ); void getOptions( Ms3dFilter::Ms3dOptions * o ); public slots: void helpNowEvent(); void subVersionChangedEvent(); protected: void updateExtraEnabled(); }; bool ms3dprompt_show( Model * model, ModelFilter::Options * o ); #endif // __MS3DPROMPT_H mm3d-master/src/implui/msgqt.cc000066400000000000000000000105721324021725400167440ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "msg.h" #include #include extern "C" void msgqt_info( const char * str ) { QMessageBox::information( NULL, QString("Misfit 3D"), QString::fromUtf8(str), QMessageBox::Ok, 0 ); } extern "C" void msgqt_warning( const char * str ) { QMessageBox::warning( NULL, QString("Misfit 3D"), QString::fromUtf8(str), QMessageBox::Ok, 0 ); } extern "C" void msgqt_error( const char * str ) { QMessageBox::critical( NULL, QString("Misfit 3D"), QString::fromUtf8(str), QMessageBox::Ok, 0 ); } typedef enum { MsgInfo, MsgWarning, MsgError } MessageType; static char _msgqt_info_common( MessageType type, const QString & str, const char * opts ) { int button[3]; bool done = false; for ( int t = 0; t < 3; t++ ) { if( ! done && opts[t] ) { switch ( toupper( opts[t] ) ) { case 'Y': button[t] = QMessageBox::Yes; break; case 'N': button[t] = QMessageBox::No; break; case 'C': button[t] = QMessageBox::Cancel | QMessageBox::Escape; break; case 'O': button[t] = QMessageBox::Ok; break; case 'A': button[t] = QMessageBox::Abort; break; case 'R': button[t] = QMessageBox::Retry; break; case 'I': button[t] = QMessageBox::Ignore; break; default: button[t] = QMessageBox::NoButton; break; } if ( isupper( opts[t] ) ) { button[t] |= QMessageBox::Default; } } else { done = true; button[t] = 0; } } int result = 0; switch ( type ) { case MsgError: result = QMessageBox::critical( NULL, QString("Misfit 3D"), str, button[0], button[1], button[2] ); break; case MsgWarning: result = QMessageBox::warning( NULL, QString("Misfit 3D"), str, button[0], button[1], button[2] ); break; case MsgInfo: default: result = QMessageBox::information( NULL, QString("Misfit 3D"), str, button[0], button[1], button[2] ); break; } char rval = '!'; switch ( result ) { case QMessageBox::Ok: rval = 'O'; break; case QMessageBox::Yes: rval = 'Y'; break; case QMessageBox::No: rval = 'N'; break; case QMessageBox::Abort: rval = 'A'; break; case QMessageBox::Retry: rval = 'R'; break; case QMessageBox::Ignore: rval = 'I'; break; case QMessageBox::Cancel: default: rval = 'C'; break; } return rval; } // Do you want to save first (yes, no, cancel) [Y/n/c]? // Do you want to save first (abort, retry, ignore) [A/r/i]? extern "C" char msgqt_info_prompt( const char * str, const char * opts ) { return _msgqt_info_common( MsgInfo, QString::fromUtf8(str), opts ); } extern "C" char msgqt_warning_prompt( const char * str, const char * opts ) { return _msgqt_info_common( MsgWarning, QString::fromUtf8(str), opts ); } extern "C" char msgqt_error_prompt( const char * str, const char * opts ) { return _msgqt_info_common( MsgError, QString::fromUtf8(str), opts ); } void init_msgqt() { msg_register( msgqt_info, msgqt_warning, msgqt_error ); msg_register_prompt( msgqt_info_prompt, msgqt_warning_prompt, msgqt_error_prompt ); } mm3d-master/src/implui/msgqt.h000066400000000000000000000016571324021725400166120ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MSGQT_H #define __MSGQT_H extern void init_msgqt(); #endif // __MSGQT_H mm3d-master/src/implui/mview.cc000066400000000000000000000057501324021725400167420ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "mview.h" #include "modelviewport.h" #include "viewpanel.h" #include "log.h" #include "decalmgr.h" #include #include #include #include ModelView::ModelView( Toolbox * toolbox, QWidget * parent ) : QWidget( parent ), m_toolbox( toolbox ) { setupUi( this ); QString zoomStr; zoomStr.sprintf( "%f", m_modelView->getZoomLevel() ); m_zoomInput->setText( zoomStr ); connect( m_modelView, SIGNAL(viewDirectionChanged(int)), this, SLOT(setViewDirection(int))); ViewPanel * panel = dynamic_cast(parent); if ( panel ) { connect( m_modelView, SIGNAL(modelUpdated()), panel, SLOT(modelUpdatedEvent())); } else { log_error( "cast failed, not connecting\n" ); } } ModelView::~ModelView() { DecalManager::getInstance()->unregisterToolParent( m_modelView ); } void ModelView::freeTextures() { m_modelView->freeTextures(); } void ModelView::setViewDirection( int dir ) { m_viewInput->setCurrentIndex( dir ); m_modelView->viewChangeEvent( dir ); } void ModelView::zoomLevelEnterEvent() { m_modelView->setZoomLevel( m_zoomInput->text().toDouble() ); } void ModelView::zoomInEvent() { m_modelView->zoomIn(); } void ModelView::zoomOutEvent() { m_modelView->zoomOut(); } void ModelView::setModel( Model * model ) { if ( model == NULL ) { DecalManager::getInstance()->unregisterToolParent( m_modelView ); } m_modelView->setModel( model ); m_modelView->setToolbox( m_toolbox ); if ( model ) { DecalManager::getInstance()->registerToolParent( m_modelView ); } } void ModelView::updateView() { m_modelView->updateView(); } unsigned ModelView::getViewDirection() { return m_viewInput->currentIndex(); } QString ModelView::getViewDirectionLabel() { return m_viewInput->currentText(); } void ModelView::copyContentsToTexture( Texture * tex ) { m_modelView->copyContentsToTexture( tex ); } void ModelView::updateCaptureGL() { m_modelView->updateCaptureGL(); } QImage ModelView::grabFrameBuffer( bool withAlpha ) { return m_modelView->grabFrameBuffer( withAlpha ); } mm3d-master/src/implui/mview.h000066400000000000000000000036071324021725400166030ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MVIEW_H #define __MVIEW_H #include "modelview.base.h" #include "modelviewport.h" #include class Model; class Toolbox; class Texture; class ModelView : public QWidget, public Ui::ModelViewBase { Q_OBJECT public: ModelView( Toolbox * toolbox, QWidget * parent = NULL ); virtual ~ModelView(); void freeTextures(); void setModel( Model * model ); void frameArea( double x1, double y1, double z1, double x2, double y2, double z2 ) { m_modelView->frameArea( x1, y1, z1, x2, y2, z2 ); }; void updateView(); unsigned getViewDirection(); QString getViewDirectionLabel(); void copyContentsToTexture( Texture * tex ); void updateCaptureGL(); QImage grabFrameBuffer( bool withAlpha ); ModelViewport * getModelViewport() { return m_modelView; }; public slots: void setViewDirection( int dir ); void zoomLevelEnterEvent(); void zoomInEvent(); void zoomOutEvent(); protected: Toolbox * m_toolbox; }; #endif // __MVIEW_H mm3d-master/src/implui/newanim.cc000066400000000000000000000031331324021725400172420ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "newanim.h" #include #include #include NewAnim::NewAnim( QWidget * parent ) : QDialog( parent ) { setModal( true ); setupUi( this ); m_name->setText( QString("") ); m_okButton->setEnabled( false ); } NewAnim::~NewAnim() { } QString NewAnim::getAnimName() { return m_name->text(); } bool NewAnim::isSkeletal() { return m_skeletal->isChecked(); } void NewAnim::setSkeletal( bool o ) { if ( o ) m_skeletal->setChecked( true ); else m_frame->setChecked( true ); } void NewAnim::nameChangedEvent() { if ( m_name->text().length() == 0 ) { m_okButton->setEnabled( false ); } else { m_okButton->setEnabled( true ); } } mm3d-master/src/implui/newanim.h000066400000000000000000000024501324021725400171050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __NEWANIM_H #define __NEWANIM_H #include "newanim.base.h" #include "mm3dport.h" #include #include class NewAnim : public QDialog, public Ui::NewAnimBase { Q_OBJECT public: NewAnim( QWidget * parent ); virtual ~NewAnim(); QString getAnimName(); bool isSkeletal(); void setSkeletal( bool o ); public slots: void nameChangedEvent(); }; #endif // __NEWANIM_H mm3d-master/src/implui/objprompt.cc000066400000000000000000000054031324021725400176220ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "objprompt.h" #include "objfilter.h" #include "model.h" #include "helpwin.h" #include #include #include ObjPrompt::ObjPrompt() : QDialog( NULL ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } ObjPrompt::~ObjPrompt() { } void ObjPrompt::setOptions( ObjFilter::ObjOptions * opts ) { m_normalsValue->setChecked( opts->m_saveNormals ); m_placesValue->setValue( opts->m_places ); m_texPlacesValue->setValue( opts->m_texPlaces ); m_normalPlacesValue->setValue( opts->m_normalPlaces ); } void ObjPrompt::getOptions( ObjFilter::ObjOptions * opts ) { opts->m_saveNormals = m_normalsValue->isChecked(); opts->m_places = m_placesValue->value(); opts->m_texPlaces = m_texPlacesValue->value(); opts->m_normalPlaces = m_normalPlacesValue->value(); } void ObjPrompt::helpNowEvent() { HelpWin * win = new HelpWin( "olh_objprompt.html", true ); win->show(); } // This function takes a ModelFilter::Options argument, downcasts it // to an ObjOptions object, and uses it to prompt the user for // options for the OBJ file filter. // // If you want to provide options for your format in a plugin // you'll need to call setOptionsPrompt on your filter after you // create it in your plugin_init function. // // This function is registered with the ObjFilter class when the // filter is created in stdfilters.cc. bool objprompt_show( Model * model, ModelFilter::Options * o ) { bool rval = false; ObjPrompt p; ObjFilter::ObjOptions * opts = dynamic_cast< ObjFilter::ObjOptions * >( o ); if ( opts ) { p.setOptions( opts ); if ( p.exec() ) { rval = true; p.getOptions( opts ); } } else { rval = true; } return rval; } mm3d-master/src/implui/objprompt.h000066400000000000000000000026101324021725400174610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __OBJPROMPT_H #define __OBJPROMPT_H #include "objprompt.base.h" #include "modelfilter.h" #include "objfilter.h" #include class Model; class ObjPrompt : public QDialog, public Ui::ObjPromptBase { Q_OBJECT public: ObjPrompt(); virtual ~ObjPrompt(); void setOptions( ObjFilter::ObjOptions * o ); void getOptions( ObjFilter::ObjOptions * o ); public slots: void helpNowEvent(); protected: }; bool objprompt_show( Model * model, ModelFilter::Options * o ); #endif // __OBJPROMPT_H mm3d-master/src/implui/painttexturewin.cc000066400000000000000000000172261324021725400210660ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "painttexturewin.h" #include "textureframe.h" #include "texwidget.h" #include "model.h" #include "texture.h" #include "log.h" #include "misc.h" #include "3dmprefs.h" #include "msg.h" #include "decalmgr.h" #include "helpwin.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include #include PaintTextureWin::PaintTextureWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ), m_saved( false ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); m_textureFrame->setModel( model ); m_textureWidget = m_textureFrame->getTextureWidget(); m_textureWidget->setInteractive( false ); m_textureWidget->setMouseOperation( TextureWidget::MouseRange ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); bool foundTexture = false; list triangles; m_model->getSelectedTriangles( triangles ); int material = -1; list::iterator it; for ( it = triangles.begin(); !foundTexture && it != triangles.end(); it++ ) { int g = m_model->getTriangleGroup( triangles.front() ); int m = m_model->getGroupTextureId( g ); if ( m >= 0 ) { m_textureFrame->textureChangedEvent( m + 1 ); foundTexture = true; material = m; } } if ( !foundTexture ) { log_error( "no group selected\n" ); } addTriangles(); m_polygonsButton->setCurrentIndex( 2 ); m_verticesButton->setCurrentIndex( 0 ); m_hSize->setCurrentIndex( 3 ); m_vSize->setCurrentIndex( 3 ); if ( material >= 0 ) { Texture * tex = m_model->getTextureData( material ); if ( tex ) { int x = tex->m_width; int y = tex->m_height; if ( x == y ) { m_hSize->setCurrentIndex( 3 ); m_vSize->setCurrentIndex( 3 ); } else if ( y > x ) { m_hSize->setCurrentIndex( 2 ); m_vSize->setCurrentIndex( 5 ); int index = 2; while ( y > x ) { y = y / 2; index++; } m_vSize->setCurrentIndex( index ); } else { m_vSize->setCurrentIndex( 2 ); m_hSize->setCurrentIndex( 5 ); int index = 2; while ( x > y ) { x = x / 2; index++; } m_hSize->setCurrentIndex( index ); } } } else { m_textureFrame->textureChangedEvent( 0 ); } // TODO allow background, or remove clear button m_clearButton->hide(); m_textureWidget->setSolidBackground( true ); updateDisplay(); } PaintTextureWin::~PaintTextureWin() { } void PaintTextureWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_painttexturewin.html", true ); win->show(); } void PaintTextureWin::accept() { QDialog::accept(); } void PaintTextureWin::textureSizeChangeEvent() { updateDisplay(); } void PaintTextureWin::displayChangedEvent() { updateDisplay(); } void PaintTextureWin::clearEvent() { m_textureWidget->setSolidBackground( true ); m_textureWidget->updateGL(); } void PaintTextureWin::saveEvent() { const char * modelFile = m_model->getFilename(); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( modelFile && modelFile[0] != '\0' ) { std::string fullname; std::string fullpath; std::string basename; normalizePath( modelFile, fullname, fullpath, basename ); dir = tr( fullpath.c_str() ); } bool again = true; while ( again ) { again = false; QString filename = QFileDialog::getSaveFileName( this, tr("File name for saved texture?"), dir, QString("PNG Images (*.png *.PNG)") ); if ( filename.length() > 0 ) { bool save = true; if ( file_exists( filename.toUtf8() ) ) { char val = msg_warning_prompt( (const char *) tr( "File exists. Overwrite?" ).toUtf8(), "yNc" ); switch ( val ) { case 'N': again = true; // We want to fall through here case 'C': save = false; break; default: break; } } if ( save ) { int h = atoi( m_hSize->currentText().toLatin1() ); // This is a total hack. For some reason Qt refuses to repaint // the widget here. To force an update I have to resize the // OpenGL widget, repaint, and then resize it back to the // original size. It's an ugly hack, but it makes this function // work. { int hack_w = m_textureWidget->width(); int hack_h = m_textureWidget->height(); m_textureWidget->resize( 4, 4 ); m_textureWidget->updateGL(); m_textureWidget->resize( hack_w, hack_h ); } QImage img = m_textureWidget->grabFrameBuffer( false ); img = img.scaledToWidth( h, Qt::SmoothTransformation ); if ( !img.save( filename, "PNG", 100 ) ) { QString msg = tr( "Could not write file: " ) + QString( "\n" ); msg += filename; msg_error( (const char *) msg.toUtf8() ); } updateDisplay(); } } else { log_debug( "save frame buffer cancelled\n" ); } } } void PaintTextureWin::addTriangles() { m_textureWidget->clearCoordinates(); list triangles; m_model->getSelectedTriangles( triangles ); list::iterator it; float u = 0.0f; float v = 0.0f; for( it = triangles.begin(); it != triangles.end(); it++ ) { int t; int vert[3]; for ( t = 0; t < 3; t++ ) { m_model->getTextureCoords( (*it), t, u, v ); vert[t] = m_textureWidget->addVertex( u, v ); } m_textureWidget->addTriangle( vert[0], vert[1], vert[2] ); } } void PaintTextureWin::updateDisplay() { int dm = m_polygonsButton->currentIndex(); dm++; m_textureWidget->setDrawMode( static_cast(dm) ); m_textureWidget->setDrawVertices( (m_verticesButton->currentIndex() != 0) ? true : false ); m_textureFrame->sizeOverride( atoi( m_hSize->currentText().toLatin1() ), atoi( m_vSize->currentText().toLatin1() ) ); m_textureWidget->updateGL(); } mm3d-master/src/implui/painttexturewin.h000066400000000000000000000032501324021725400207200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PAINTTEXTUREWIN_H #define __PAINTTEXTUREWIN_H #include #include "painttexturewin.base.h" #include #include using std::list; using std::map; #include class Model; class TextureWidget; class PaintTextureWin : public QDialog, public Ui::PaintTextureWinBase { Q_OBJECT public: PaintTextureWin( Model * model, QWidget * parent = NULL ); ~PaintTextureWin(); public slots: void helpNowEvent(); virtual void textureSizeChangeEvent(); virtual void displayChangedEvent(); virtual void clearEvent(); virtual void saveEvent(); void accept(); protected: void updateDisplay(); void addTriangles(); TextureWidget * m_textureWidget; Model * m_model; bool m_saved; }; #endif // __PAINTTEXTUREWIN_H mm3d-master/src/implui/paintwidget.cc000066400000000000000000000042501324021725400201240ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "paintwidget.h" #include "texwidget.h" #include "log.h" PaintWidget::PaintWidget( TextureWidget * drawBuddy, QWidget * parent ) : QGLWidget( parent ), m_drawBuddy( drawBuddy ) { } PaintWidget::~PaintWidget() { } void PaintWidget::initializeGL() { glEnable( GL_TEXTURE_2D ); setAutoBufferSwap( false ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LEQUAL ); glClearColor( 0.0, 0.0, 0.0, 1.0 ); glClearDepth( 1.0f ); GLfloat ambient[] = { 0.8f, 0.8f, 0.8f, 1.0f }; GLfloat diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat position[] = { 0.0f, 0.0f, 3.0f, 0.0f }; glLightModeli( GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE ); glLightfv( GL_LIGHT0, GL_AMBIENT, ambient ); glLightfv( GL_LIGHT0, GL_DIFFUSE, diffuse ); glLightfv( GL_LIGHT0, GL_POSITION, position ); glDisable( GL_LIGHT0 ); glDisable( GL_LIGHTING ); } void PaintWidget::resizeGL( int w, int h ) { glViewport( 0, 0, ( GLint ) w, ( GLint ) h ); glMatrixMode( GL_PROJECTION ); glLoadIdentity( ); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity( ); } void PaintWidget::paintGL() { // I don't draw on myself log_debug( "PaintWidget::paintGL\n" ); m_drawBuddy->paintOnGlWidget( this ); swapBuffers(); } mm3d-master/src/implui/paintwidget.h000066400000000000000000000024441324021725400177710ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PAINTWIDGET_H #define __PAINTWIDGET_H #include #include #include class TextureWidget; class PaintWidget : public QGLWidget { public: PaintWidget( TextureWidget * drawBuddy, QWidget * parent = NULL ); virtual ~PaintWidget(); protected: void initializeGL(); void paintGL(); void resizeGL( int w, int h ); TextureWidget * m_drawBuddy; }; #endif // __PAINTWIDGET_H mm3d-master/src/implui/pluginwin.cc000066400000000000000000000054561324021725400176320ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "pluginmgr.h" #include "pluginwin.h" #include "helpwin.h" #include #include PluginWindow::PluginWindow() : QDialog( NULL ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( false ); m_pluginList->header()->setSectionsClickable( false ); m_pluginList->header()->setSectionsMovable( false ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); refreshPluginData(); } PluginWindow::~PluginWindow() { } void PluginWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_pluginwin.html", true ); win->show(); } void PluginWindow::refreshPluginData() { PluginManager * pmgr = PluginManager::getInstance(); list plist = pmgr->getPluginIds(); list::iterator it; for ( it = plist.begin(); it != plist.end(); it++ ) { QTreeWidgetItem * item = new QTreeWidgetItem( m_pluginList ); item->setText( 0, QString( pmgr->getPluginName( *it ) ) + " " ); item->setText( 1, QString( pmgr->getPluginVersion( *it ) ) + " " ); item->setText( 2, QString( pmgr->getPluginDescription( *it ) ) + " " ); const char * status = "Unknown"; switch ( pmgr->getPluginStatus( *it ) ) { case PluginManager::PluginActive: status = "Active"; break; case PluginManager::PluginUserDisabled: status = "Disabled by user"; break; case PluginManager::PluginVersionDisabled: status = "Disabled (incompatible version)"; break; case PluginManager::PluginNotPlugin: status = "Not a plugin"; break; case PluginManager::PluginError: status = "Error"; break; default: status = "Unknown status code"; break; } item->setText( 3, QString(status) + " " ); } } mm3d-master/src/implui/pluginwin.h000066400000000000000000000023111324021725400174570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PLUGINWIN_H #define __PLUGINWIN_H #include "pluginwin.base.h" #include class PluginWindow : public QDialog, public Ui::PluginWinBase { Q_OBJECT public: PluginWindow(); virtual ~PluginWindow(); public slots: void helpNowEvent(); protected: void refreshPluginData(); }; #endif // __PLUGINWIN_H mm3d-master/src/implui/pointwin.cc000066400000000000000000000100711324021725400174520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "pointwin.h" #include "decalmgr.h" #include "helpwin.h" #include #include #include #include #include using std::list; #include "model.h" #include "decalmgr.h" #include "log.h" #include "msg.h" #include "modelstatus.h" PointWin::PointWin( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); int t; for ( t = 0; t < m_model->getPointCount(); t++ ) { m_pointName->insertItem( t, QString::fromUtf8( m_model->getPointName(t) ) ); } for ( t = 0; t < m_model->getBoneJointCount(); t++ ) { m_pointJoint->insertItem( t + 1, QString::fromUtf8( m_model->getBoneJointName(t) ) ); } list points; m_model->getSelectedPoints( points ); if ( ! points.empty() ) { m_pointName->setCurrentIndex( points.front() ); pointNameSelected( points.front() ); } else { m_pointName->setCurrentIndex( 0 ); pointNameSelected( 0 ); } } PointWin::~PointWin() { } void PointWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_pointwin.html", true ); win->show(); } void PointWin::pointNameSelected( int index ) { if ( index < m_pointName->count() ) { m_model->unselectAllPoints(); m_model->selectPoint( index ); m_deleteButton->setEnabled( true ); m_renameButton->setEnabled( true ); m_pointJoint->setEnabled( true ); m_pointJoint->setCurrentIndex( m_model->getPointBoneJoint( index ) + 1 ); DecalManager::getInstance()->modelUpdated( m_model ); } else { m_deleteButton->setEnabled( false ); m_renameButton->setEnabled( false ); m_pointJoint->setEnabled( false ); m_pointJoint->setCurrentIndex( 0 ); } } void PointWin::pointJointSelected( int index ) { if ( m_pointName->count() > 0 ) { if ( index >= 0 && index < m_pointJoint->count() ) { m_model->setPointBoneJoint( m_pointName->currentIndex(), index - 1 ); } } } void PointWin::deleteClicked() { if ( m_pointName->count() ) { m_model->deletePoint( m_pointName->currentIndex() ); } } void PointWin::renameClicked() { if ( m_pointName->count() ) { bool ok = false; int pointNum = m_pointName->currentIndex(); QString pointName = QInputDialog::getText( this, tr("Rename point", "window title"), tr("Enter new point name:"), QLineEdit::Normal, QString::fromUtf8( m_model->getPointName( pointNum )), &ok ); if ( ok ) { m_model->setPointName( pointNum, pointName.toUtf8() ); m_pointName->setItemText( pointNum, pointName ); } } } void PointWin::accept() { log_debug( "Point changes complete\n" ); m_model->operationComplete( tr( "Point changes", "operation complete" ).toUtf8() ); QDialog::accept(); } void PointWin::reject() { log_debug( "Point changes canceled\n" ); m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } mm3d-master/src/implui/pointwin.h000066400000000000000000000027341324021725400173230ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POINTWIN_H #define __POINTWIN_H #include "pointwin.base.h" #include class Model; class Q3Accel; class PointWin : public QDialog, public Ui::PointWinBase { Q_OBJECT public: PointWin( Model * model, QWidget * parent = NULL ); virtual ~PointWin(); public slots: void helpNowEvent(); void deleteClicked(); void renameClicked(); void pointNameSelected( int index ); void pointJointSelected( int index ); protected slots: void accept(); void reject(); protected: Q3Accel * m_accel; Model * m_model; }; #endif // __POINTWIN_H mm3d-master/src/implui/projectionwin.cc000066400000000000000000000313551324021725400205050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "projectionwin.h" #include "decalmgr.h" #include "helpwin.h" #include "textureframe.h" #include "texwidget.h" #include "decalmgr.h" #include #include #include #include #include #include #include using std::list; #include "model.h" #include "decalmgr.h" #include "log.h" #include "msg.h" #include "modelstatus.h" ProjectionWin::ProjectionWin( Model * model, QWidget * parent, ViewPanel * viewPanel ) : QDialog( parent ), m_viewPanel( viewPanel ), m_undoCount( 0 ), m_redoCount( 0 ), m_inUndo( false ), m_ignoreChange( false ) { setupUi( this ); m_material->hide(); m_materialLabel->hide(); m_textureWidget = m_textureFrame->getTextureWidget(); m_textureWidget->setInteractive( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseRange ); m_textureWidget->setDrawVertices( false ); m_textureWidget->setMouseTracking( true ); connect( m_textureWidget, SIGNAL(updateRangeSignal()), this, SLOT(rangeChangedEvent()) ); connect( m_textureWidget, SIGNAL(updateRangeDoneSignal()), this, SLOT(applyProjectionEvent()) ); connect( m_textureWidget, SIGNAL(updateSeamSignal(double,double)), this, SLOT(seamChangedEvent(double,double)) ); connect( m_textureWidget, SIGNAL(updateSeamDoneSignal()), this, SLOT(applyProjectionEvent()) ); connect( m_textureWidget, SIGNAL(zoomLevelChanged(QString)), this, SLOT(zoomLevelChangedEvent(QString)) ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); QShortcut * undo = new QShortcut( QKeySequence( tr("CTRL+Z", "Undo shortcut")), this ); connect( undo, SIGNAL(activated()), this, SLOT(undoEvent()) ); QShortcut * redo = new QShortcut( QKeySequence( tr("CTRL+Y", "Redo shortcut")), this ); connect( redo, SIGNAL(activated()), this, SLOT(redoEvent()) ); // can't do this until constructor is done (because of Model::Observer interface) //setModel( model ); } ProjectionWin::~ProjectionWin() { } void ProjectionWin::refreshProjectionDisplay() { m_textureWidget->clearCoordinates(); if ( m_projection->count() > 0 ) { int proj = m_projection->currentIndex(); unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { int p = m_model->getTriangleProjection( t ); if ( p == proj ) { int g = m_model->getTriangleGroup( t ); if ( g >= 0 ) { int material = m_model->getGroupTextureId( g ); if ( material >= 0 ) { m_textureFrame->textureChangedEvent( material + 1 ); // TODO bah, off-by-one, I need to fix this addProjectionTriangles(); return; } } } } } m_textureWidget->updateGL(); m_textureFrame->textureChangedEvent( -1 ); DecalManager::getInstance()->modelUpdated( m_model ); } void ProjectionWin::modelChanged( int changeBits ) { if ( !m_ignoreChange ) { if ( !m_inUndo ) { m_undoCount = 0; m_redoCount = 0; } // TODO need some way to re-select the projection we were looking at if ( isVisible() ) { int projCount = m_model->getProjectionCount(); if ( projCount != m_projection->count() ) { // A projection was added or deleted, we need to select a new // projection and re-initialize everything. initWindow(); } else { // a change to projection itself, or a non-projection change, just // re-initialize the projection display for the current projection int p = m_projection->currentIndex(); m_projection->setItemText( p, QString::fromUtf8( m_model->getProjectionName( p )) ); m_type->setCurrentIndex( m_model->getProjectionType( p ) ); // TODO material/test pattern? addProjectionTriangles(); } } } } void ProjectionWin::addProjectionTriangles() { m_textureWidget->clearCoordinates(); int p = getSelectedProjection(); double uv[4] = { 0, 0, 0, 0 }; m_model->getProjectionRange( p, uv[0], uv[1], uv[2], uv[3] ); m_textureWidget->setRange( uv[0], uv[1], uv[2], uv[3] ); unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->getTriangleProjection( t ) == p ) { int verts[3] = { 0, 0, 0 }; for ( int i = 0; i < 3; i++ ) { float u = 1.0; float v = 1.0; m_model->getTextureCoords( t, i, u, v ); verts[i] = m_textureWidget->addVertex( u, v ); } m_textureWidget->addTriangle( verts[0], verts[1], verts[2] ); } } m_textureWidget->updateGL(); DecalManager::getInstance()->modelUpdated( m_model ); } void ProjectionWin::setModel( Model * model ) { m_undoCount = 0; m_redoCount = 0; if ( model != m_model ) { model->addObserver( this ); } m_model = model; m_textureFrame->setModel( model ); if ( isVisible() ) { initWindow(); } } void ProjectionWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_projectionwin.html", true ); win->show(); } void ProjectionWin::undoEvent() { if ( m_undoCount > 0 ) { m_inUndo = true; m_model->undo(); m_undoCount--; m_inUndo = false; } } void ProjectionWin::redoEvent() { if ( m_undoCount < m_redoCount ) { m_inUndo = true; m_model->redo(); m_undoCount++; m_inUndo = false; } } void ProjectionWin::show() { setModel( m_model ); if ( !isVisible() ) { // If we are visible, setModel already did this initWindow(); } QDialog::show(); } void ProjectionWin::initWindow() { m_projection->clear(); if ( m_model ) { unsigned pcount = m_model->getProjectionCount(); bool enabled = true; if ( pcount == 0 ) { enabled = false; } m_type->setEnabled( enabled ); m_material->setEnabled( enabled ); m_textureFrame->setEnabled( enabled ); m_addFacesButton->setEnabled( enabled ); m_removeFacesButton->setEnabled( enabled ); m_renameButton->setEnabled( enabled ); m_zoomInput->setEnabled( enabled ); m_zoomInButton->setEnabled( enabled ); m_zoomOutButton->setEnabled( enabled ); m_applyButton->setEnabled( enabled ); m_resetButton->setEnabled( enabled ); if ( enabled ) { for ( unsigned p = 0; p < pcount; p++ ) { m_projection->insertItem( p, QString::fromUtf8( m_model->getProjectionName(p) ) ); } bool found = false; for ( unsigned p = 0; p < pcount; p++ ) { if ( m_model->isProjectionSelected( p ) ) { found = true; m_projection->setCurrentIndex( p ); projectionIndexChangedEvent( p ); break; } } if ( !found ) { unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { int p = m_model->getTriangleProjection( t ); if ( p >= 0 ) { m_projection->setCurrentIndex( p ); projectionIndexChangedEvent( p ); break; } } } } } } } void ProjectionWin::closeEvent( QCloseEvent * e ) { e->ignore(); hide(); } void ProjectionWin::zoomIn() { m_textureWidget->zoomIn(); } void ProjectionWin::zoomOut() { m_textureWidget->zoomOut(); } void ProjectionWin::typeChangedEvent( int type ) { int p = getSelectedProjection(); if ( p >= 0 ) { m_model->setProjectionType( p, type ); //m_model->applyProjection( p ); operationComplete( tr( "Set Projection Type", "operation complete" ).toUtf8() ); } refreshProjectionDisplay(); } void ProjectionWin::addFacesEvent() { int p = getSelectedProjection(); unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { m_model->setTriangleProjection( t, p ); } } m_model->applyProjection( p ); operationComplete( tr( "Set Triangle Projection", "operation complete" ).toUtf8() ); refreshProjectionDisplay(); } void ProjectionWin::removeFacesEvent() { unsigned tcount = m_model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( m_model->isTriangleSelected( t ) ) { m_model->setTriangleProjection( t, -1 ); } } operationComplete( tr( "Set Triangle Projection", "operation complete" ).toUtf8() ); refreshProjectionDisplay(); } void ProjectionWin::applyProjection() { int p = getSelectedProjection(); if ( p >= 0 ) { m_model->applyProjection( p ); } addProjectionTriangles(); } void ProjectionWin::applyProjectionEvent() { applyProjection(); operationComplete( tr("Apply Projection", "operation complete").toUtf8() ); } void ProjectionWin::resetClickedEvent() { int p = getSelectedProjection(); m_model->setProjectionRange( p, 0.0, 0.0, 1.0, 1.0 ); operationComplete( tr( "Reset UV Coordinates", "operation complete" ).toUtf8() ); addProjectionTriangles(); //applyProjectionEvent(); } void ProjectionWin::renameClickedEvent() { int p = getSelectedProjection(); if ( p >= 0 ) { bool ok = false; QString projName = QInputDialog::getText( this, tr("Rename projection", "window title"), tr("Enter new point name:"), QLineEdit::Normal, QString::fromUtf8( m_model->getProjectionName( p )), &ok ); if ( ok ) { m_model->setProjectionName( p, projName.toUtf8() ); m_projection->setItemText( p, projName ); operationComplete( tr( "Rename Projection", "operation complete" ).toUtf8() ); } } } void ProjectionWin::projectionIndexChangedEvent( int newIndex ) { int type = m_model->getProjectionType( newIndex ); m_type->setCurrentIndex( type ); double uv[4] = { 0, 0, 0, 0 }; m_model->getProjectionRange( newIndex, uv[0], uv[1], uv[2], uv[3] ); m_textureWidget->setRange( uv[0], uv[1], uv[2], uv[3] ); refreshProjectionDisplay(); } void ProjectionWin::zoomChangeEvent() { double zoom = m_zoomInput->text().toDouble(); if ( zoom < 0.00001 ) { zoom = 1; } m_textureWidget->setZoomLevel( zoom ); } void ProjectionWin::zoomLevelChangedEvent( QString zoomStr ) { m_zoomInput->setText( zoomStr ); } void ProjectionWin::rangeChangedEvent() { int p = getSelectedProjection(); double uv[4] = { 0, 0, 0, 0 }; m_textureWidget->getRange( uv[0], uv[1], uv[2], uv[3] ); m_model->setProjectionRange( p, uv[0], uv[1], uv[2], uv[3] ); addProjectionTriangles(); } void ProjectionWin::seamChangedEvent( double xDiff, double yDiff ) { if ( fabs( xDiff ) > 0.0 ) { int p = getSelectedProjection(); double up[4] = { 0, 0, 0, 1 }; double seam[4] = { 0, 0, 0, 1 }; m_model->getProjectionUp( p, up ); m_model->getProjectionSeam( p, seam ); Matrix m; m.setRotationOnAxis( up, xDiff ); m.apply3( seam ); m_model->setProjectionSeam( p, seam ); addProjectionTriangles(); } } int ProjectionWin::getSelectedProjection() { if ( m_projection->count() > 0 ) { return m_projection->currentIndex(); } return -1; } void ProjectionWin::operationComplete( const char * opname ) { m_undoCount++; m_redoCount = m_undoCount; m_ignoreChange = true; m_model->operationComplete( opname ); m_ignoreChange = false; } mm3d-master/src/implui/projectionwin.h000066400000000000000000000046731324021725400203520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POINTWIN_H #define __POINTWIN_H #include "projectionwin.base.h" #include "model.h" #include #include class ViewPanel; class TextureWidget; class ProjectionWin : public QDialog, public Ui::ProjectionWinBase, public Model::Observer { Q_OBJECT public: ProjectionWin( Model * model, QWidget * parent, ViewPanel * viewPanel ); virtual ~ProjectionWin(); void refreshProjectionDisplay(); void addProjectionTriangles(); // Model::Observer methods void modelChanged( int changeBits ); public slots: void show(); void setModel( Model * m ); void zoomIn(); void zoomOut(); void undoEvent(); void redoEvent(); void helpNowEvent(); protected slots: void closeEvent( QCloseEvent * e ); void typeChangedEvent(int); void addFacesEvent(); void removeFacesEvent(); void applyProjectionEvent(); void resetClickedEvent(); void renameClickedEvent(); void projectionIndexChangedEvent(int); void zoomChangeEvent(); void zoomLevelChangedEvent( QString zoomStr ); void rangeChangedEvent(); void seamChangedEvent( double xDiff, double yDiff ); protected: void initWindow(); void applyProjection(); int getSelectedProjection(); void operationComplete( const char * opname ); Model * m_model; ViewPanel * m_viewPanel; TextureWidget * m_textureWidget; int m_undoCount; int m_redoCount; bool m_inUndo; bool m_ignoreChange; }; #endif // __POINTWIN_H mm3d-master/src/implui/qtmain.cc000066400000000000000000000140711324021725400171000ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "qtmain.h" #include "globalmenubar.h" #include "viewwin.h" #include "model.h" #include "sysconf.h" #include "config.h" #include #include #include #include #include #include #include #include #include #include "log.h" #include "mm3dport.h" #include "misc.h" #include "msg.h" #include "msgqt.h" #include "3dmprefs.h" #include "cmdline.h" #include "mlocale.h" // Handle macOS opening file in finder or dropping file on dock icon. // File types must be listed in AppBundle.app/Contents/Info.plist. class MisfitApp : public QApplication { public: MisfitApp(int &argc, char **argv) : QApplication(argc, argv) { } bool event(QEvent *event) { if ( event->type() == QEvent::FileOpen ) { QFileOpenEvent *openEvent = static_cast(event); ViewWindow::openModelInEmptyWindow( openEvent->file().toUtf8() ); } return QApplication::event(event); } }; static MisfitApp * s_app = NULL; static QTranslator * s_qtXlat = NULL; static QTranslator * s_mm3dXlat = NULL; static GlobalMenuBar* s_globalMenuBar = NULL; static bool _has_gl_support() { if ( ! QGLFormat::hasOpenGL() ) { log_error( "No openGL support, exiting...\n" ); return false; } QGLFormat format = QGLFormat::defaultFormat(); format.setDoubleBuffer( true ); format.setRgba( true ); format.setAlpha( true ); QGLFormat::setDefaultFormat( format ); format = QGLFormat::defaultFormat(); log_debug( "qt says alpha is%s enabled\n", (format.alpha() ? "" : " not" ) ); return true; } static void _cleanup() { // TODO add any necessary cleanup } static bool loadTranslationFile( QTranslator * xlat, const QString & localeFile ) { std::list path_list; path_list.push_back( "." ); path_list.push_back( "../i18n" ); path_list.push_back( getI18nDirectory() ); // try current directory first (for override), then mm3d system directory for ( std::list::iterator it = path_list.begin(); it != path_list.end(); ++it ) { log_debug( "attempting to load translation %s from %s\n", (const char *) localeFile.toUtf8(), (const char *) it->c_str() ); if ( s_qtXlat->load( localeFile, it->c_str() ) ) { log_debug( " loaded.\n" ); return true; } } log_warning( "unable to load translation for %s\n", (const char *) localeFile.toUtf8() ); return false; } QApplication * ui_getapp() { return s_app; } int ui_prep( int & argc, char * argv[] ) { s_app = new MisfitApp( argc, argv ); QString loc = mlocale_get().c_str(); if ( loc == "" ) { loc = QLocale::system().name(); } // General Qt translations s_qtXlat = new QTranslator( 0 ); QString qtLocale = QString( "qt_" ) + loc; loadTranslationFile( s_qtXlat, qtLocale ); s_app->installTranslator( s_qtXlat ); // MM3D translations s_mm3dXlat = new QTranslator( 0 ); QString mm3dLocale = QString( "mm3d_" ) + loc; loadTranslationFile( s_mm3dXlat, mm3dLocale ); s_app->installTranslator( s_mm3dXlat ); return 0; } int ui_init( int & argc, char * argv[] ) { int rval = 0; if ( !s_app ) { ui_prep( argc, argv ); } if ( cmdline_runcommand ) { rval = cmdline_command(); } if ( cmdline_runui ) { if ( ! _has_gl_support() ) { return -1; } #ifdef Q_OS_MAC // Keep the program running with no windows on macOS (as programs typically do) s_app->setQuitOnLastWindowClosed( false ); s_globalMenuBar = new GlobalMenuBar(); #endif bool opened = false; unsigned openCount = 0; init_msgqt(); openCount = cmdline_getOpenModelCount(); if ( openCount == 0 ) { for ( int t = 1; t < argc; t++ ) { char pwd[ PATH_MAX ]; getcwd( pwd, PATH_MAX ); std::string file = normalizePath( argv[t], pwd ); if ( ViewWindow::openModel( file.c_str() ) ) { openCount++; opened = true; } } } else { for ( unsigned t = 0; t < openCount; t++ ) { Model * m = cmdline_getOpenModel( t ); ViewWindow * win = new ViewWindow( m ); win->getSaved(); // Just so I don't have a warning opened = true; } cmdline_clearOpenModelList(); } if ( opened ) { rval = s_app->exec(); } else { ViewWindow * win = new ViewWindow( new Model ); win->getSaved(); // Just so I don't have a warning rval = s_app->exec(); /* StartPrompt p; p.exec(); if ( !p.shouldExit() ) { rval = s_app->exec(); } */ } _cleanup(); } if ( s_globalMenuBar ) { delete s_globalMenuBar; } delete s_mm3dXlat; delete s_qtXlat; delete s_app; s_app = NULL; s_qtXlat = NULL; s_mm3dXlat = NULL; return rval; } void ui_exit() { _cleanup(); if ( qApp ) { qApp->quit(); } else { exit( 0 ); } } mm3d-master/src/implui/qtmain.h000066400000000000000000000021121324021725400167330ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __QTMAIN_H #define __QTMAIN_H class QApplication; extern QApplication * ui_getapp(); extern int ui_prep( int & argc, char * argv[] ); extern int ui_init( int & argc, char * argv[] ); extern void ui_exit(); #endif // __QTMAIN_H mm3d-master/src/implui/qttex.cc000066400000000000000000000261631324021725400167610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "qttex.h" //Added by qt3to4: #include "mm3dconfig.h" #include "log.h" #include #include #include #include #include #include #include #include using std::list; using std::string; QtTextureFilter::QtTextureFilter() : m_initialized( false ) { } QtTextureFilter::~QtTextureFilter() { } bool QtTextureFilter::canRead( const char * filename ) { initializeSupported(); if ( filename == NULL ) { return false; } QString cmpstr; unsigned len = strlen( filename ); QStringList::Iterator it; for ( it = m_read.begin(); it != m_read.end(); it++ ) { cmpstr = QString(".") + *it; if ( (int) len >= (int) cmpstr.length() ) { if ( strcasecmp( &filename[len-cmpstr.length()], (const char *) cmpstr.toUtf8()) == 0 ) { return true; } } } return false; } bool QtTextureFilter::canWrite( const char * filename ) { initializeSupported(); if ( filename == NULL ) { return false; } QString cmpstr; unsigned len = strlen( filename ); QStringList::Iterator it; for ( it = m_write.begin(); it != m_write.end(); it++ ) { cmpstr = QString(".") + *it; if ( (int) len >= (int) cmpstr.length() ) { if ( strcasecmp( &filename[len-cmpstr.length()], (const char *) cmpstr.toUtf8()) == 0 ) { return true; } } } return false; } Texture::ErrorE QtTextureFilter::readFile( Texture * texture, const char * filename ) { initializeSupported(); QImage image; if ( filename == NULL ) { log_error( "filename NULL\n" ); return Texture::ERROR_NO_FILE; } if ( texture == NULL ) { log_error( "texture NULL\n" ); return Texture::ERROR_UNKNOWN; } if ( image.load( QString::fromUtf8( filename ) ) ) { imageToTexture( texture, &image ); texture->m_filename = strdup( filename ); const char * name = strrchr( filename, DIR_SLASH ); if ( name ) { texture->m_name = strdup( &name[1] ); } else { texture->m_name = strdup( filename ); } char * ext = strrchr( texture->m_name, '.' ); if ( ext ) { ext[0] = '\0'; } return Texture::ERROR_NONE; } else { return Texture::ERROR_FILE_OPEN; } return Texture::ERROR_UNKNOWN; } Texture::ErrorE QtTextureFilter::readMemory( const char * format, Texture * texture, const ImageData * d ) { initializeSupported(); if ( format == NULL || texture == NULL || d == NULL ) { log_error( "bad argument\n" ); return Texture::ERROR_UNKNOWN; } char fmt[5] = "PNG"; getFormatString( fmt, format ); log_debug( "loading image from data for %s, size %d\n", fmt, d->getDataSize() ); const uint8_t * ptr = d->getConstDataPtr(); if ( ptr == NULL ) { log_error( "ImageData data pointer is null\n" ); return Texture::ERROR_UNKNOWN; } QImage image; if ( image.loadFromData( ptr, d->getDataSize() ) ) { imageToTexture( texture, &image ); texture->m_filename = (char *) malloc( 20 ); sprintf( texture->m_filename, "%p", texture ); texture->m_name = (char *) malloc( 20 ); strcpy( texture->m_name, texture->m_filename ); return Texture::ERROR_NONE; } else { log_debug( "load failed\n" ); return Texture::ERROR_FILE_READ; } return Texture::ERROR_UNKNOWN; } Texture::ErrorE QtTextureFilter::writeFile( Texture * texture, const char * filename ) { initializeSupported(); if ( filename == NULL ) { log_error( "filename NULL\n" ); return Texture::ERROR_NO_FILE; } if ( texture == NULL ) { log_error( "texture NULL\n" ); return Texture::ERROR_UNKNOWN; } uint8_t * data = new uint8_t[ texture->m_width * texture->m_height * 4 ]; textureToImage( texture, data ); char fmt[5] = "PNG"; getFormatString( fmt, filename ); Texture::ErrorE err = Texture::ERROR_NONE; { QImage image ( data, texture->m_width, texture->m_height, QImage::Format_ARGB32 ); if ( ! image.save( QString::fromUtf8( filename ), fmt, 100 ) ) { return Texture::ERROR_FILE_WRITE; } } delete[] data; // Must do this after image goes out of scope return err; } Texture::ErrorE QtTextureFilter::writeMemory( const char * format, Texture * texture, TextureFilter::ImageData ** d ) { initializeSupported(); if ( format == NULL ) { log_error( "filename NULL\n" ); return Texture::ERROR_NO_FILE; } if ( texture == NULL || d == NULL ) { log_error( "texture NULL\n" ); return Texture::ERROR_UNKNOWN; } uint8_t * data = new uint8_t[ texture->m_width * texture->m_height * 4 ]; textureToImage( texture, data ); char fmt[5] = "PNG"; getFormatString( fmt, format ); Texture::ErrorE err = Texture::ERROR_NONE; { QImage image ( data, texture->m_width, texture->m_height, QImage::Format_ARGB32 ); QByteArray ba; QBuffer buffer( &ba ); buffer.open( QIODevice::WriteOnly ); if ( ! image.save( &buffer, fmt, 100 ) ) { return Texture::ERROR_FILE_WRITE; } *d = TextureFilter::ImageData::get( ba.size() ); memcpy( (*d)->getDataPtr(), ba.data(), ba.size() ); } delete[] data; // Must do this after image goes out of scope return err; } list QtTextureFilter::getReadTypes() { initializeSupported(); list rval; QStringList::Iterator it; for ( it = m_read.begin(); it != m_read.end(); it++ ) { rval.push_back( (const char *) (QString("*.") + *it).toUtf8() ); } return rval; } list QtTextureFilter::getWriteTypes() { initializeSupported(); list rval; QStringList::Iterator it; for ( it = m_write.begin(); it != m_write.end(); it++ ) { rval.push_back( (const char *) (QString("*.") + *it).toUtf8() ); } return rval; } //------------------------------------------------------------------ // Protected members //------------------------------------------------------------------ void QtTextureFilter::getFormatString( char * format, const char * filename ) { const char * ext = strrchr( filename, '.' ); if ( ext ) { ext++; // Skip '.' } else { ext = (char *) filename; } strncpy( format, ext, 5 ); for ( unsigned t = 0; format[t]; t++ ) { format[t] = toupper( format[t] ); } if ( strcmp( format, "JPG" ) == 0 ) { strcpy( format, "JPEG" ); } if ( strcmp( format, "TIF" ) == 0 ) { strcpy( format, "TIFF" ); } } void QtTextureFilter::textureToImage( Texture * texture, uint8_t * data ) { unsigned sbpp = ( texture->m_format == Texture::FORMAT_RGB ) ? 3 : 4; unsigned dbpp = 4; uint8_t * src; uint8_t * dest; for ( int y = 0; y < texture->m_height; y++ ) { for ( int x = 0; x < texture->m_width; x++ ) { src = &texture->m_data[ ((texture->m_height - y - 1) * texture->m_width + x) * sbpp ]; dest = &data[ (y * texture->m_width + x) * dbpp ]; dest[ 0 ] = src[ 2 ]; dest[ 1 ] = src[ 1 ]; dest[ 2 ] = src[ 0 ]; if ( texture->m_format == Texture::FORMAT_RGBA ) { dest[ 3 ] = src[3]; } else { dest[ 3 ] = 0xff; } } } } void QtTextureFilter::imageToTexture( Texture * texture, QImage * image ) { texture->m_width = image->width(); texture->m_height = image->height(); bool hasAlpha = image->hasAlphaChannel(); log_debug( "Alpha channel: %s\n", hasAlpha ? "present" : "not present" ); unsigned pixelBytes = hasAlpha ? 4 : 3; unsigned pixelCount = texture->m_width * texture->m_height; unsigned imageSize = pixelCount * (pixelBytes * sizeof(uint8_t)); texture->m_data = new uint8_t[ imageSize ]; // Make bottom row the first row, as required by OpenGL if ( hasAlpha ) { texture->m_format = Texture::FORMAT_RGBA; for ( int y = 0; y < texture->m_height; y ++ ) { for ( int x = 0; x < texture->m_width; x++ ) { QRgb p = image->pixel( x, texture->m_height - y - 1 ); texture->m_data[ ((y * texture->m_width + x)*4) + 0 ] = qRed( p ); texture->m_data[ ((y * texture->m_width + x)*4) + 1 ] = qGreen( p ); texture->m_data[ ((y * texture->m_width + x)*4) + 2 ] = qBlue( p ); texture->m_data[ ((y * texture->m_width + x)*4) + 3 ] = qAlpha( p ); } } } else { texture->m_format = Texture::FORMAT_RGB; for ( int y = 0; y < texture->m_height; y ++ ) { for ( int x = 0; x < texture->m_width; x++ ) { QRgb p = image->pixel( x, texture->m_height - y - 1 ); texture->m_data[ ((y * texture->m_width + x)*3) + 0 ] = qRed( p ); texture->m_data[ ((y * texture->m_width + x)*3) + 1 ] = qGreen( p ); texture->m_data[ ((y * texture->m_width + x)*3) + 2 ] = qBlue( p ); } } } } void QtTextureFilter::initializeSupported() { if ( !m_initialized ) { m_initialized = true; { QList< QByteArray > list = QImageReader::supportedImageFormats(); for ( QList< QByteArray >::iterator it = list.begin(); it != list.end(); it++ ) { const char * str = (*it).constData(); m_read.push_back( QString(str) ); if ( strcasecmp( str, "JPEG" ) == 0 ) { m_read.push_back( QString("JPG") ); } if ( strcasecmp( str, "TIFF" ) == 0 ) { m_read.push_back( QString("TIF") ); } } } { QList< QByteArray > list = QImageWriter::supportedImageFormats(); for ( QList< QByteArray >::iterator it = list.begin(); it != list.end(); it++ ) { const char * str = (*it).constData(); m_write.push_back( QString(str) ); if ( strcasecmp( str, "JPEG" ) == 0 ) { m_write.push_back( QString("JPG") ); } if ( strcasecmp( str, "TIFF" ) == 0 ) { m_write.push_back( QString("TIF") ); } } } } } mm3d-master/src/implui/qttex.h000066400000000000000000000036551324021725400166240ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __QTTEX_H #define __QTTEX_H #include "texmgr.h" #include class QImage; class QtTextureFilter : public TextureFilter { public: QtTextureFilter(); virtual ~QtTextureFilter(); std::list< std::string > getReadTypes(); std::list< std::string > getWriteTypes(); Texture::ErrorE readFile( Texture * texture, const char * filename ); Texture::ErrorE writeFile( Texture * texture, const char * filename ); bool canRead( const char * filename ); bool canWrite( const char * filename ); Texture::ErrorE readMemory( const char * format, Texture * texture, const ImageData * d ); Texture::ErrorE writeMemory( const char * format, Texture * texture, ImageData ** d ); protected: void initializeSupported(); void imageToTexture( Texture * texture, QImage * image ); void textureToImage( Texture * texture, uint8_t * data ); void getFormatString( char * format, const char * filename ); bool m_initialized; QStringList m_read; QStringList m_write; }; #endif // __QTTEX_H mm3d-master/src/implui/rgbawin.cc000066400000000000000000000075311324021725400172430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "rgbawin.h" #include "helpwin.h" #include "log.h" #include #include #include #include #include RgbaWin::RgbaWin( QWidget * parent ) : QDialog( parent ), m_editing( false ) { setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } RgbaWin::~RgbaWin() { } void RgbaWin::helpNowEvent() { HelpWin * win = new HelpWin( "olh_rgbawin.html", true ); win->show(); } void RgbaWin::redSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_redEdit->setText( str ); } emit valuesChanged(); } void RgbaWin::greenSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_greenEdit->setText( str ); } emit valuesChanged(); } void RgbaWin::blueSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_blueEdit->setText( str ); } emit valuesChanged(); } void RgbaWin::alphaSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100 ); m_alphaEdit->setText( str ); } emit valuesChanged(); } void RgbaWin::redEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_redSlider->setValue( (int) (v * 100) ); m_editing = false; } void RgbaWin::greenEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_greenSlider->setValue( (int) (v * 100) ); m_editing = false; } void RgbaWin::blueEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_blueSlider->setValue( (int) (v * 100) ); m_editing = false; } void RgbaWin::alphaEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_alphaSlider->setValue( (int) (v * 100) ); m_editing = false; } float RgbaWin::getRed() { return (float) m_redSlider->value() / 100.0; } float RgbaWin::getGreen() { return (float) m_greenSlider->value() / 100.0; } float RgbaWin::getBlue() { return (float) m_blueSlider->value() / 100.0; } float RgbaWin::getAlpha() { return (float) m_alphaSlider->value() / 100.0; } void RgbaWin::setLabel( const char * newLabel ) { if ( newLabel ) { setWindowTitle( QString( newLabel ) ); QString str; str.sprintf( "%s", newLabel ); m_propertyLabel->setText( str ); } } void RgbaWin::setRed( const float & v ) { m_redSlider->setValue( (int) (v * 100) ); } void RgbaWin::setGreen( const float & v ) { m_greenSlider->setValue( (int) (v * 100) ); } void RgbaWin::setBlue( const float & v ) { m_blueSlider->setValue( (int) (v * 100) ); } void RgbaWin::setAlpha( const float & v ) { m_alphaSlider->setValue( (int) (v * 100) ); } mm3d-master/src/implui/rgbawin.h000066400000000000000000000041251324021725400171010ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __RGBAWIN_H #define __RGBAWIN_H #include "rgbawin.base.h" #include class RgbaWin : public QDialog, public Ui::RgbaWinBase { Q_OBJECT public: RgbaWin( QWidget * parent = NULL ); virtual ~RgbaWin(); void setLabel( const char * newLabel ); float getRed(); float getGreen(); float getBlue(); float getAlpha(); void setRed( const float & v ); void setGreen( const float & v ); void setBlue( const float & v ); void setAlpha( const float & v ); signals: void valuesChanged(); public slots: void helpNowEvent(); void redSliderChanged( int ); void greenSliderChanged( int ); void blueSliderChanged( int ); void alphaSliderChanged( int ); void redEditChanged( const QString & ); void greenEditChanged( const QString & ); void blueEditChanged( const QString & ); void alphaEditChanged( const QString & ); protected: // We don't want to update the edit box if the user is typing in it // So we set this to true when editing. When we update the slider, // our slot will check this value. If false, it will update the edit box bool m_editing; }; #endif // __RGBAWIN_H mm3d-master/src/implui/spherifywin.cc000066400000000000000000000113471324021725400201610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "spherifywin.h" #include "helpwin.h" #include "model.h" #include "glmath.h" #include "decalmgr.h" #include "log.h" #include #include #include #include #include SpherifyWin::SpherifyWin( Model * model, QWidget * parent ) : ValueWin( parent ), m_model( model ) { setAttribute( Qt::WA_DeleteOnClose ); setLabel( "Spherify" ); m_valueSlider->setMinimum( -100 ); m_valueEdit->setText( QString("0") ); double min[3] = { 0.0, 0.0, 0.0 }; double max[3] = { 0.0, 0.0, 0.0 }; bool haveCenter = false; SpherifyPosition sv; std::list posList; m_model->getSelectedPositions( posList ); std::list::iterator it; for ( it = posList.begin(); it != posList.end(); it++ ) { sv.pos = (*it); m_model->getPositionCoords( (*it), sv.coords ); if ( haveCenter ) { min[0] = sv.coords[0] < min[0] ? sv.coords[0] : min[0]; min[1] = sv.coords[1] < min[1] ? sv.coords[1] : min[1]; min[2] = sv.coords[2] < min[2] ? sv.coords[2] : min[2]; max[0] = sv.coords[0] > max[0] ? sv.coords[0] : max[0]; max[1] = sv.coords[1] > max[1] ? sv.coords[1] : max[1]; max[2] = sv.coords[2] > max[2] ? sv.coords[2] : max[2]; } else { min[0] = sv.coords[0]; min[1] = sv.coords[1]; min[2] = sv.coords[2]; max[0] = sv.coords[0]; max[1] = sv.coords[1]; max[2] = sv.coords[2]; haveCenter = true; } m_positions.push_back( sv ); } m_center[0] = (min[0] + max[0]) / 2.0; m_center[1] = (min[1] + max[1]) / 2.0; m_center[2] = (min[2] + max[2]) / 2.0; m_radius = 0.0; { SpherifyPositionList::iterator it; for ( it = m_positions.begin(); it != m_positions.end(); it++ ) { double dist = distance( m_center[0], m_center[1], m_center[2], (*it).coords[0], (*it).coords[1], (*it).coords[2] ); m_radius = dist > m_radius ? dist : m_radius; } } log_debug( "center is %f,%f,%f\n", m_center[0], m_center[1], m_center[2] ); log_debug( "radius is %f\n", m_radius ); } SpherifyWin::~SpherifyWin() { } void SpherifyWin::showHelp() { HelpWin * win = new HelpWin( "olh_spherifywin.html", true ); win->show(); } void SpherifyWin::valueSliderChanged( int v ) { log_debug( "changed\n" ); if ( v > 100 ) { v = 100; } if ( v < -100 ) { v = -100; } double percent = (double) v / 100.0; double diff[4] = { 0.0, 0.0, 0.0, 0.0 }; SpherifyPositionList::iterator it; for ( it = m_positions.begin(); it != m_positions.end(); it++ ) { diff[0] = (*it).coords[0] - m_center[0]; diff[1] = (*it).coords[1] - m_center[1]; diff[2] = (*it).coords[2] - m_center[2]; Vector vec( diff ); vec.normalize3(); diff[0] = vec.get( 0 ) * m_radius + m_center[0]; diff[1] = vec.get( 1 ) * m_radius + m_center[1]; diff[2] = vec.get( 2 ) * m_radius + m_center[2]; diff[0] = (diff[0] - (*it).coords[0]) * percent + (*it).coords[0]; diff[1] = (diff[1] - (*it).coords[1]) * percent + (*it).coords[1]; diff[2] = (diff[2] - (*it).coords[2]) * percent + (*it).coords[2]; m_model->movePosition( (*it).pos, diff[0], diff[1], diff[2] ); } DecalManager::getInstance()->modelUpdated( m_model ); ValueWin::valueSliderChanged( v ); } void SpherifyWin::valueEditChanged( const QString & str ) { ValueWin::valueEditChanged( str ); } void SpherifyWin::accept() { m_model->operationComplete( tr( "Spherify", "operation complete" ).toUtf8() ); DecalManager::getInstance()->modelUpdated( m_model ); ValueWin::accept(); } void SpherifyWin::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); ValueWin::reject(); } mm3d-master/src/implui/spherifywin.h000066400000000000000000000032041324021725400200140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SPHERIFYWIN_H #define __SPHERIFYWIN_H #include "valuewin.h" #include "model.h" #include class Model; class SpherifyWin : public ValueWin { Q_OBJECT public: SpherifyWin( Model * model, QWidget * parent = NULL ); virtual ~SpherifyWin(); public slots: void valueEditChanged( const QString & ); void valueSliderChanged( int ); void accept(); void reject(); protected: virtual void showHelp(); typedef struct _SpherifyPosition_t { Model::Position pos; double coords[3]; } SpherifyPosition; typedef std::list SpherifyPositionList; Model * m_model; double m_center[3]; double m_radius; SpherifyPositionList m_positions; }; #endif // __SPHERIFYWIN_H mm3d-master/src/implui/statusbar.cc000066400000000000000000000157571324021725400176330ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "statusbar.h" #include "mm3dport.h" #include "model.h" #include "misc.h" #include #include #include #include #include #include using std::map; map StatusBar::s_modelMap; StatusBar::StatusBar( Model * model, QWidget * parent ) : QWidget( parent ), m_model( model ), m_queueDisplay( false ) { setupUi( this ); m_palette = this->palette(); this->setAutoFillBackground( true ); m_statusLabel->setAutoFillBackground( true ); m_labelFrame->setAutoFillBackground( true ); s_modelMap[ m_model ] = this; } StatusBar::~StatusBar() { s_modelMap.erase( m_model ); } StatusObject * StatusBar::getStatusBarFromModel( Model * model ) { if ( s_modelMap.find( model ) != s_modelMap.end() ) { return s_modelMap[ model ]; } else { return NULL; } } void StatusBar::setModel( Model * model ) { s_modelMap.erase( m_model ); m_model = model; s_modelMap[ m_model ] = this; } void StatusBar::setText( const char * str ) { setToolTip(""); if ( utf8len( str ) > 72 ) { char * temp = strdup( str ); setToolTip( QString::fromUtf8(temp) ); utf8strtrunc( temp, 69 ); strcat( temp, "..." ); m_statusLabel->setText( QString::fromUtf8(temp) ); free( temp ); } else { m_statusLabel->setText( QString::fromUtf8(str) ); } } void StatusBar::addText( StatusTypeE type, unsigned ms, const char * str ) { if ( m_queueDisplay ) { // Clear non-errors first bool removing = true; size_t max_queue_size = 2; while ( removing && m_queue.size() > max_queue_size ) { removing = false; std::list< TextQueueItemT >::iterator it; for ( it = m_queue.begin(); it != m_queue.end(); it++ ) { if ( (*it).type != StatusError ) { m_queue.erase( it ); it = m_queue.end(); removing = true; } } } // If we still have more than max_queue_size in the queue, and the // new message is an error, start removing the oldest errors. if ( m_queue.size() > max_queue_size ) { if ( type != StatusError ) return; while ( m_queue.size() > max_queue_size ) m_queue.pop_front(); } TextQueueItemT tqi; tqi.str = QString::fromUtf8( str ); tqi.ms = ms; tqi.type = type; m_queue.push_back( tqi ); } else { setText( str ); QTimer::singleShot( ms, this, SLOT(timerExpired())); if ( type == StatusError ) { QPalette p = m_palette; p.setColor( QPalette::WindowText, QColor( 255, 255, 255 ) ); p.setColor( QPalette::Window, QColor( 255, 0, 0 ) ); m_labelFrame->setPalette( p ); } m_queueDisplay = true; } } void StatusBar::timerExpired() { m_labelFrame->setPalette( m_palette ); if ( !m_queue.empty() ) { TextQueueItemT tqi = m_queue.front(); m_queue.pop_front(); setText( tqi.str.toUtf8() ); m_queueDisplay = true; if ( tqi.type == StatusError ) { QPalette p = m_palette; p.setColor( QPalette::WindowText, QColor( 255, 255, 255 ) ); p.setColor( QPalette::Window, QColor( 255, 0, 0 ) ); m_labelFrame->setPalette( p ); } if ( tqi.ms > 0 ) { QTimer::singleShot( tqi.ms, this, SLOT(timerExpired())); } else { timerExpired(); } } else { m_queueDisplay = false; } } void StatusBar::setVertices( unsigned v, unsigned sv ) { QString statChar = tr( "V:", "Vertices status bar label" ); QString str; if ( sv ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), sv, v ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), v ); } m_vertexLabel->setText( QString(str) ); } void StatusBar::setFaces( unsigned f, unsigned sf ) { QString statChar = tr( "F:", "Faces status bar label" ); QString str; if ( sf ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), sf, f ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), f ); } m_faceLabel->setText( QString(str) ); } void StatusBar::setGroups( unsigned g, unsigned sg ) { QString statChar = tr( "G:", "Groups status bar label" ); QString str; if ( sg ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), sg, g ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), g ); } m_groupLabel->setText( QString(str) ); } void StatusBar::setBoneJoints( unsigned b, unsigned sb ) { QString statChar = tr( "B:", "Bone Joints status bar label" ); QString str; if ( sb ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), sb, b ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), b ); } m_boneLabel->setText( QString(str) ); } void StatusBar::setPoints( unsigned b, unsigned sb ) { QString statChar = tr( "P:", "Points status bar label" ); QString str; if ( sb ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), sb, b ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), b ); } m_pointLabel->setText( QString(str) ); } void StatusBar::setTextures( unsigned t, unsigned st ) { QString statChar = tr( "M:", "Materials status bar label" ); QString str; if ( st ) { str.sprintf( "%s%d/%d", (const char *) statChar.toUtf8(), st, t ); } else { str.sprintf( "%s%d", (const char *) statChar.toUtf8(), t ); } m_textureLabel->setText( QString(str) ); } extern "C" void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) { static char temp[1024]; va_list ap; va_start( ap, fmt ); PORT_vsnprintf( temp, sizeof(temp), fmt, ap ); StatusObject * bar = StatusBar::getStatusBarFromModel( model ); if ( bar ) { bar->addText( type, ms, temp ); } else { if ( type == StatusError ) { model->pushError( temp ); } } } mm3d-master/src/implui/statusbar.h000066400000000000000000000045021324021725400174570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __STATUSBAR_H #define __STATUSBAR_H #include "statusbar.base.h" #include "modelstatus.h" #include #include #include #include class Model; class StatusBar : public QWidget, public Ui::StatusBarBase, public StatusObject { Q_OBJECT public: static StatusObject * getStatusBarFromModel( Model * model ); StatusBar( Model * model, QWidget * parent ); virtual ~StatusBar(); Model * getModel() { return m_model; }; void setModel( Model * m_model ); // Status text void setText( const char * str ); void addText( StatusTypeE type, unsigned ms, const char * str ); // Second (optional) argument is num selected void setVertices( unsigned v, unsigned sv = 0 ); void setFaces( unsigned f, unsigned sf = 0 ); void setGroups( unsigned g, unsigned sg = 0 ); void setBoneJoints( unsigned b, unsigned sb = 0 ); void setPoints( unsigned p, unsigned sp = 0 ); void setTextures( unsigned t, unsigned st = 0 ); public slots: void timerExpired(); protected: struct _TextQueueItem_t { StatusTypeE type; unsigned ms; QString str; }; typedef struct _TextQueueItem_t TextQueueItemT; Model * m_model; QPalette m_palette; std::list m_queue; bool m_queueDisplay; static std::map< Model *, StatusBar * > s_modelMap; }; #endif // __STATUSBAR_H mm3d-master/src/implui/texturecoord.cc000066400000000000000000000525421324021725400203430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "texturecoord.h" #include "textureframe.h" #include "texwidget.h" #include "model.h" #include "mapdirection.h" #include "log.h" #include "decalmgr.h" #include "helpwin.h" #include "keycfg.h" #include "3dmprefs.h" #include #include #include #include #include #include #include #include #include #include TextureCoord::TextureCoord( Model * model, QWidget * parent ) : QDialog( parent ), m_undoCount( 0 ), m_redoCount( 0 ), m_inUndo( false ), m_ignoreChange( false ), m_currentDirection( 0 ), m_currentMapScheme( 2 ) // if you change this, change the setChecked line below also { setupUi( this ); // TODO handle undo of select/unselect? // Can't do this until after constructor is done because of observer interface //setModel( m_model ); m_textureFrame->setModel( model ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); QShortcut * undo = new QShortcut( QKeySequence( tr("CTRL+Z", "Undo shortcut")), this ); connect( undo, SIGNAL(activated()), this, SLOT(undoEvent()) ); QShortcut * redo = new QShortcut( QKeySequence( tr("CTRL+Y", "Redo shortcut")), this ); connect( redo, SIGNAL(activated()), this, SLOT(redoEvent()) ); QShortcut * select = new QShortcut( g_keyConfig.getKey( "tool_select_vertices" ), this ); connect( select, SIGNAL(activated()), this, SLOT(toolSelectEvent()) ); QShortcut * move = new QShortcut( g_keyConfig.getKey( "tool_move" ), this ); connect( move, SIGNAL(activated()), this, SLOT(toolMoveEvent()) ); QShortcut * rotate = new QShortcut( g_keyConfig.getKey( "tool_rotate" ), this ); connect( rotate, SIGNAL(activated()), this, SLOT(toolRotateEvent()) ); QShortcut * scale = new QShortcut( g_keyConfig.getKey( "tool_scale" ), this ); connect( scale, SIGNAL(activated()), this, SLOT(toolScaleEvent()) ); m_textureWidget = m_textureFrame->getTextureWidget(); m_textureWidget->setInteractive( true ); m_textureWidget->setDrawBorder( true ); g_prefs.setDefault( "ui_texcoord_scale_aspect", 0 ); g_prefs.setDefault( "ui_texcoord_scale_center", 1 ); bool aspect = ( g_prefs( "ui_texcoord_scale_aspect" ).intValue() != 0 ); bool center = ( g_prefs( "ui_texcoord_scale_center" ).intValue() != 0 ); m_scaleAspect->setChecked( aspect ); m_scaleCenter->setChecked( center ); m_textureWidget->setScaleKeepAspect( m_scaleAspect->isChecked() ); m_textureWidget->setScaleFromCenter( m_scaleCenter->isChecked() ); connect( m_textureWidget, SIGNAL(updateCoordinatesSignal()), this, SLOT(updateTextureCoordsEvent())); connect( m_textureWidget, SIGNAL(updateSelectionDoneSignal()), this, SLOT(updateSelectionDoneEvent())); connect( m_textureWidget, SIGNAL(updateCoordinatesDoneSignal()), this, SLOT(updateDoneEvent())); connect( m_textureWidget, SIGNAL(zoomLevelChanged(QString)), this, SLOT(zoomLevelChangedEvent(QString)) ); m_selectButton->setChecked( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseSelect ); m_groupButton->setChecked( true ); // if you change this, change m_currentMapScheme also g_prefs.setDefault( "ui_texcoord_lines_color", 0xffffff ); g_prefs.setDefault( "ui_texcoord_selection_color", 0xff0000 ); uint32_t linesColor = g_prefs( "ui_texcoord_lines_color" ).intValue(); uint32_t selectionColor = g_prefs( "ui_texcoord_selection_color" ).intValue(); m_textureWidget->setLinesColor( linesColor ); m_textureWidget->setSelectionColor( selectionColor ); int linesIndex = 0; linesIndex |= (linesColor & 0x800000) ? 4 : 0 ; linesIndex |= (linesColor & 0x008000) ? 2 : 0 ; linesIndex |= (linesColor & 0x000080) ? 1 : 0 ; m_linesColor->setCurrentIndex( linesIndex ); int selectionIndex = 0; selectionIndex |= (selectionColor & 0x800000) ? 4 : 0 ; selectionIndex |= (selectionColor & 0x008000) ? 2 : 0 ; selectionIndex |= (selectionColor & 0x000080) ? 1 : 0 ; m_selectionColor->setCurrentIndex( selectionIndex ); } TextureCoord::~TextureCoord() { } void TextureCoord::undoEvent() { if ( m_undoCount > 0 ) { m_inUndo = true; m_model->undo(); m_undoCount--; m_inUndo = false; m_textureWidget->restoreSelectedUv(); m_textureWidget->updateGL(); } } void TextureCoord::redoEvent() { if ( m_undoCount < m_redoCount ) { m_inUndo = true; m_model->redo(); m_undoCount++; m_inUndo = false; m_textureWidget->updateGL(); } } void TextureCoord::operationComplete( const char * opname ) { m_undoCount++; m_redoCount = m_undoCount; m_ignoreChange = true; m_model->operationComplete( opname ); m_ignoreChange = false; } void TextureCoord::show() { setModel( m_model ); if ( !isVisible() ) { // If we are visible, setModel already did this initWindow(); } QDialog::show(); } void TextureCoord::initWindow() { m_textureWidget->clearCoordinates(); bool foundTexture = false; list trilist; m_model->getSelectedTriangles( trilist ); list::iterator it; for ( it = trilist.begin(); !foundTexture && it != trilist.end(); it++ ) { int g = m_model->getTriangleGroup( trilist.front() ); int m = m_model->getGroupTextureId( g ); if ( m >= 0 ) { // FIXME cache current texture value and don't change it if we // don't have to (to prevent resetting zoom and center) m_textureFrame->textureChangedEvent( m + 1 ); foundTexture = true; } } if ( !foundTexture ) { log_error( "no group selected\n" ); } useGroupCoordinates(); DecalManager::getInstance()->modelUpdated( m_model ); if ( m_inUndo ) m_textureWidget->restoreSelectedUv(); else m_textureWidget->saveSelectedUv(); m_textureWidget->updateGL(); } void TextureCoord::setModel( Model * model ) { m_undoCount = 0; m_redoCount = 0; if ( model != m_model ) { model->addObserver( this ); } m_model = model; m_textureFrame->setModel( model ); if ( isVisible() ) { initWindow(); } } void TextureCoord::helpNowEvent() { HelpWin * win = new HelpWin( "olh_texturecoordwin.html", true ); win->show(); } void TextureCoord::toolSelectEvent() { m_selectButton->setChecked( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseSelect ); m_textureWidget->updateGL(); } void TextureCoord::toolMoveEvent() { m_moveButton->setChecked( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseMove ); m_textureWidget->updateGL(); } void TextureCoord::toolRotateEvent() { m_rotateButton->setChecked( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseRotate ); m_textureWidget->updateGL(); } void TextureCoord::toolScaleEvent() { m_scaleButton->setChecked( true ); m_textureWidget->setMouseOperation( TextureWidget::MouseScale ); m_textureWidget->updateGL(); } void TextureCoord::mapGroupEvent() { if ( m_currentMapScheme == MapSchemeGroup ) { return; } MapDirection dir(this); dir.setMapDirection( getDefaultDirection() ); if ( dir.exec() ) { mapGroup( dir.getMapDirection() ); } else { cancelMapChange(); return; } m_textureWidget->updateGL(); } void TextureCoord::resetClickedEvent() { if ( m_currentMapScheme == MapSchemeGroup ) { MapDirection dir(this); if ( dir.exec() ) { mapGroup( dir.getMapDirection() ); m_textureWidget->updateGL(); log_debug( "reset texture coordinates and map from direction %d\n", dir.getMapDirection() ); } } else { if ( QMessageBox::Ok == QMessageBox::warning( this, tr("Reset coordinates?", "window title"), tr("Are you sure you want to reset texture coordinates for this group?"), QMessageBox::Ok, QMessageBox::Cancel ) ) { log_debug( "reset texture coordinates\n" ); switch ( m_currentMapScheme ) { case MapSchemeTriangle: mapTriangle(); break; case MapSchemeQuad: mapQuad(); break; default: break; } } } } void TextureCoord::updateDoneEvent() { operationComplete( tr("Move texture coordinates").toUtf8() ); } void TextureCoord::updateSelectionDoneEvent() { m_textureWidget->saveSelectedUv(); operationComplete( tr("Select texture coordinates").toUtf8() ); } void TextureCoord::updateTextureCoordsEvent() { list trilist; m_model->getSelectedTriangles( trilist ); if ( trilist.size() > 0 ) { float s[3]; float t[3]; if ( m_currentMapScheme == 2 ) { list::iterator it; for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { m_textureWidget->getCoordinates( m_textureTriangles[ *it ].m_triangleNum, s, t ); for ( int v = 0; v < 3; v++ ) { m_model->setTextureCoords( *it, v, s[v], t[v] ); } } } } else { list::iterator it; list::iterator texIt = m_triangles.begin(); for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { if ( texIt == m_triangles.end() ) { texIt = m_triangles.begin(); } m_textureWidget->getCoordinates( *texIt, s, t ); for ( int v = 0; v < 3; v++ ) { m_model->setTextureCoords( *it, v, s[v], t[v] ); } texIt++; } } } DecalManager::getInstance()->modelUpdated( m_model ); } else { log_error( "no group selected\n" ); } } void TextureCoord::scaleSettingsChangedEvent() { m_textureWidget->setScaleKeepAspect( m_scaleAspect->isChecked() ); m_textureWidget->setScaleFromCenter( m_scaleCenter->isChecked() ); g_prefs( "ui_texcoord_scale_aspect" ) = m_scaleAspect->isChecked() ? 1 : 0; g_prefs( "ui_texcoord_scale_center" ) = m_scaleCenter->isChecked() ? 1 : 0; } void TextureCoord::rotateCcwEvent() { m_textureWidget->rotateCoordinatesCcw(); updateTextureCoordsEvent(); updateDoneEvent(); } void TextureCoord::rotateCwEvent() { m_textureWidget->rotateCoordinatesCw(); updateTextureCoordsEvent(); updateDoneEvent(); } void TextureCoord::vFlipEvent() { m_textureWidget->vFlipCoordinates(); updateTextureCoordsEvent(); updateDoneEvent(); } void TextureCoord::hFlipEvent() { m_textureWidget->hFlipCoordinates(); updateTextureCoordsEvent(); updateDoneEvent(); } void TextureCoord::selectionColorChangedEvent( int newColor ) { uint32_t rgb = 0; rgb |= (newColor & 1) ? 0x0000ff : 0; rgb |= (newColor & 2) ? 0x00ff00 : 0; rgb |= (newColor & 4) ? 0xff0000 : 0; m_textureWidget->setSelectionColor( rgb ); m_textureWidget->updateGL(); g_prefs( "ui_texcoord_selection_color" ) = (int) rgb; } void TextureCoord::linesColorChangedEvent( int newColor ) { uint32_t rgb = 0; rgb |= (newColor & 1) ? 0x0000ff : 0; rgb |= (newColor & 2) ? 0x00ff00 : 0; rgb |= (newColor & 4) ? 0xff0000 : 0; m_textureWidget->setLinesColor( rgb ); m_textureWidget->updateGL(); g_prefs( "ui_texcoord_lines_color" ) = (int) rgb; } void TextureCoord::zoomIn() { m_textureWidget->zoomIn(); } void TextureCoord::zoomOut() { m_textureWidget->zoomOut(); } void TextureCoord::zoomChangeEvent() { double zoom = m_zoomInput->text().toDouble(); if ( zoom < 0.00001 ) { zoom = 1; } m_textureWidget->setZoomLevel( zoom ); } void TextureCoord::zoomLevelChangedEvent( QString zoomStr ) { m_zoomInput->setText( zoomStr ); } void TextureCoord::mapTriangle() { if ( MapSchemeTriangle == m_currentMapScheme ) { return; } m_currentMapScheme = MapSchemeTriangle; m_textureWidget->clearCoordinates(); clearTriangles(); double min = 0.0; //m_textureWidget->getMinViewCoord(); double max = 1.0; //m_textureWidget->getMaxViewCoord(); int v1 = m_textureWidget->addVertex( min, max ); int v2 = m_textureWidget->addVertex( min, min ); int v3 = m_textureWidget->addVertex( max, min ); m_triangles.push_back( m_textureWidget->addTriangle( v1, v2, v3 ) ); updateTextureCoordsEvent(); updateDoneEvent(); m_textureWidget->updateGL(); } void TextureCoord::mapQuad() { if ( MapSchemeQuad == m_currentMapScheme ) { return; } m_currentMapScheme = MapSchemeQuad; m_textureWidget->clearCoordinates(); clearTriangles(); double min = 0.0; //m_textureWidget->getMinViewCoord(); double max = 1.0; //m_textureWidget->getMaxViewCoord(); int v1 = m_textureWidget->addVertex( min, max ); int v2 = m_textureWidget->addVertex( max, max ); int v3 = m_textureWidget->addVertex( min, min ); int v4 = m_textureWidget->addVertex( max, min ); m_triangles.push_back( m_textureWidget->addTriangle( v4, v2, v1 ) ); m_triangles.push_back( m_textureWidget->addTriangle( v1, v3, v4 ) ); updateTextureCoordsEvent(); updateDoneEvent(); m_textureWidget->updateGL(); } void TextureCoord::mapGroup( int direction ) { log_debug( "mapGroup( %d )\n", direction ); m_currentMapScheme = MapSchemeGroup; double range = 1.0; //m_textureWidget->getMaxViewCoord() - m_textureWidget->getMinViewCoord(); double xOff = 0.0; //m_textureWidget->getMinViewCoord(); double yOff = xOff; m_textureWidget->clearCoordinates(); clearTriangles(); m_textureTriangles.clear(); m_textureVertices.clear(); bool setBounds = true; double xMin = 0.0; double yMin = 0.0; double xMax = 0.0; double yMax = 0.0; double coord[2]; list trilist; m_model->getSelectedTriangles( trilist ); if ( trilist.size() > 0 ) { list::iterator it; for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { for ( int t = 0; t < 3; t++ ) { int v = m_model->getTriangleVertex( *it, t ); m_model->getVertexCoords2d( v, static_cast (direction+1), coord ); if ( setBounds ) { xMin = xMax = coord[0]; yMin = yMax = coord[1]; setBounds = false; } else { if ( coord[0] < xMin ) { xMin = coord[0]; } else if ( coord[0] > xMax ) { xMax = coord[0]; } if ( coord[1] < yMin ) { yMin = coord[1]; } else if ( coord[1] > yMax ) { yMax = coord[1]; } } } } } log_debug( "Bounds = (%f,%f) - (%f,%f)\n", xMin, yMin, xMax, yMax ); for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { int t; int vert[3]; for ( t = 0; t < 3; t++ ) { int v = m_model->getTriangleVertex( *it, t ); m_model->getVertexCoords2d( v, static_cast (direction+1), coord ); if ( m_textureVertices.find( v ) != m_textureVertices.end() ) { vert[t] = m_textureVertices[ v ]; } else { vert[t] = m_textureWidget->addVertex( (((coord[0] - xMin) / (xMax - xMin)) * range) + xOff, (((coord[1] - yMin) / (yMax - yMin)) * range) + yOff); m_textureVertices[ v ] = vert[t]; } } int tri = m_textureWidget->addTriangle( vert[0], vert[1], vert[2] ); TextureTriangleT texTri; texTri.m_triangleNum = tri; for ( t = 0; t < 3; t++ ) { texTri.m_vertexNum[t] = vert[t]; } m_textureTriangles[ *it ] = texTri; m_triangles.push_back( tri ); } } } else { log_error( "no triangles selected\n" ); } updateTextureCoordsEvent(); updateDoneEvent(); m_textureWidget->updateGL(); } void TextureCoord::clearTriangles() { while ( m_triangles.size() ) { m_triangles.pop_front(); } } void TextureCoord::close() { hide(); } void TextureCoord::useGroupCoordinates() { m_textureTriangles.clear(); m_textureVertices.clear(); float m = 0.0; list trilist; m_model->getSelectedTriangles( trilist ); if ( trilist.size() > 0 ) { list::iterator it; for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { float tCoord; float sCoord; int vert[3]; int t; for ( t = 0; t < 3; t++ ) { m_model->getTextureCoords( *it, t, sCoord, tCoord ); vert[t] = m_textureWidget->addVertex( sCoord, tCoord ); sCoord = fabs( sCoord ); tCoord = fabs( tCoord ); sCoord = ( sCoord > tCoord ) ? sCoord : tCoord; if ( sCoord > m ) { m = sCoord; } } int tri = m_textureWidget->addTriangle( vert[0], vert[1], vert[2] ); TextureTriangleT texTri; texTri.m_triangleNum = tri; for ( t = 0; t < 3; t++ ) { texTri.m_vertexNum[t] = vert[t]; } m_textureTriangles[ *it ] = texTri; m_triangles.push_back( tri ); } } log_debug( "max texture coordinate value is %f\n", m ); } else { log_error( "no group selected\n" ); } } int TextureCoord::getDefaultDirection() { list trilist; m_model->getSelectedTriangles( trilist ); if ( trilist.size() > 0 ) { list::iterator it; float total[3]; float normal[3]; int t; for ( t = 0; t < 3; t++ ) { total[t] = 0; } for( it = trilist.begin(); it != trilist.end(); it++ ) { if ( m_model->isTriangleSelected( *it ) ) { for ( t = 0; t < 3; t++ ) { m_model->getNormal( *it, t, normal ); for ( int v = 0; v < 3; v++ ) { total[v] += normal[v]; } } } } int index = 0; for ( t = 1; t < 3; t++ ) { if ( fabs(total[t]) > fabs(total[index]) ) { index = t; } } switch( index ) { case 0: if ( total[index] >= 0.0 ) { return 3; } else { return 2; } break; case 1: if ( total[index] >= 0.0 ) { return 4; } else { return 5; } break; case 2: if ( total[index] >= 0.0 ) { return 0; } else { return 1; } break; default: log_error( "bad normal index: %d\n", index ); return 0; } } else { log_error( "No group selected\n" ); } return 0; } void TextureCoord::cancelMapChange() { switch ( m_currentMapScheme ) { case MapSchemeTriangle: m_triangleButton->setChecked( true ); break; case MapSchemeQuad: m_quadButton->setChecked( true ); break; case MapSchemeGroup: m_groupButton->setChecked( true ); break; default: break; } } void TextureCoord::modelChanged( int changeBits ) { if ( !m_ignoreChange ) { if ( !m_inUndo ) { m_undoCount = 0; m_redoCount = 0; } if ( isVisible() ) { initWindow(); } } } mm3d-master/src/implui/texturecoord.h000066400000000000000000000064261324021725400202050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TEXTURECOORD_H #define __TEXTURECOORD_H #include "texturecoord.base.h" #include "model.h" #include #include #include using std::list; using std::map; class TextureWidget; class TextureCoord : public QDialog, public Ui::TextureCoordBase, public Model::Observer { Q_OBJECT public: TextureCoord( Model * model, QWidget * parent = NULL ); virtual ~TextureCoord(); enum MapSchemeTypes { MapSchemeTriangle = 0, MapSchemeQuad = 1, MapSchemeGroup = 2 }; enum ToolTypes { ToolSelect = 0, ToolMove = 1, ToolScale = 2 }; // Model::Observer methods void modelChanged( int changeBits ); public slots: void show(); void helpNowEvent(); void toolSelectEvent(); void toolMoveEvent(); void toolRotateEvent(); void toolScaleEvent(); void setModel( Model * m ); virtual void resetClickedEvent(); virtual void zoomLevelChangedEvent(QString); virtual void zoomChangeEvent(); virtual void scaleSettingsChangedEvent(); virtual void updateTextureCoordsEvent(); virtual void updateSelectionDoneEvent(); virtual void updateDoneEvent(); void rotateCcwEvent(); void rotateCwEvent(); void vFlipEvent(); void hFlipEvent(); void selectionColorChangedEvent(int); void linesColorChangedEvent(int); void zoomIn(); void zoomOut(); void undoEvent(); void redoEvent(); void mapTriangle(); void mapQuad(); void mapGroupEvent(); void mapGroup( int direction ); void close(); protected: struct _TextureTriangle_t { int m_triangleNum; int m_vertexNum[3]; }; typedef struct _TextureTriangle_t TextureTriangleT; void initWindow(); void operationComplete( const char * opname ); void clearTriangles(); void useGroupCoordinates(); int getDefaultDirection(); void cancelMapChange(); TextureWidget * m_textureWidget; Model * m_model; int m_undoCount; int m_redoCount; bool m_inUndo; bool m_ignoreChange; int m_currentDirection; int m_currentMapScheme; list m_triangles; map m_textureTriangles; map m_textureVertices; }; #endif // __TEXTURECOORD_H mm3d-master/src/implui/texwin.cc000066400000000000000000000360501324021725400171260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "texwin.h" #include "textureframe.h" #include "texwidget.h" #include "model.h" #include "texture.h" #include "texmgr.h" #include "log.h" #include "rgbawin.h" #include "valuewin.h" #include "decalmgr.h" #include "msg.h" #include "3dmprefs.h" #include "helpwin.h" #include "errorobj.h" #include #include #include #include #include #include #include #include #include #include using std::list; using std::string; TextureWindow::TextureWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ), m_editing( false ), m_setting( false ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); m_textureFrame->setModel( model ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); int count = m_model->getTextureCount(); for ( int t = 0; t < count; t++ ) { //Texture * texture = m_model->getTextureData( t ); //if ( texture ) { m_textureComboBox->insertItem( t+1, QString::fromUtf8( m_model->getTextureName(t) ) ); } } int textureId = -1; list triangles; m_model->getSelectedTriangles( triangles ); list::iterator it; for ( it = triangles.begin(); it != triangles.end(); it++ ) { int g = m_model->getTriangleGroup( *it ); if ( g >= 0 ) { textureId = m_model->getGroupTextureId( g ); break; } } m_textureComboBox->setCurrentIndex( textureId + 1 ); textureChangedEvent( textureId + 1 ); m_lightingValue->setCurrentIndex(1); // Diffuse lightValueChanged( m_lightingValue->currentIndex() ); int previewIndex = 0; if ( g_prefs.exists( "ui_texwin_preview_index" ) ) { int val = g_prefs( "ui_texwin_preview_index" ).intValue(); if ( val >= 0 && val <= 1 ) { previewIndex = val; } } m_previewType->setCurrentIndex( previewIndex ); previewValueChanged( previewIndex ); } TextureWindow::~TextureWindow() { } void TextureWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_texturewin.html", true ); win->show(); } void TextureWindow::changeTextureFileEvent() { list formats = TextureManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats (", "all texture formats" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += " "; } } formatsStr += ")"; QString dir = QString::fromUtf8( g_prefs( "ui_texture_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = "."; } QFileDialog d(NULL, "", dir, formatsStr + QString(";; All Files (*)" ) ); d.setWindowTitle( tr("Open texture image") ); d.selectNameFilter( formatsStr ); int execval = d.exec(); QStringList files = d.selectedFiles(); if ( QDialog::Accepted == execval && !files.empty() ) { std::string file = (const char *) files[0].toUtf8(); QString path = d.directory().absolutePath().toUtf8(); g_prefs( "ui_texture_dir" ) = (const char *) path.toUtf8(); Texture * tex = TextureManager::getInstance()->getTexture( file.c_str() ); if ( tex ) { int textureId = m_textureComboBox->currentIndex() - 1; m_model->setMaterialTexture( textureId, tex ); log_debug( "changed texture %d to %s\n", textureId, file.c_str() ); textureChangedEvent( textureId + 1 ); } else { QString err = tr(file.c_str()) + "\n"; Texture::ErrorE e = TextureManager::getInstance()->getLastError(); if ( e != Texture::ERROR_NONE ) { err += textureErrStr( e ); } else { err += tr("Could not open file"); } msg_error( (const char *) err.toUtf8() ); } } } void TextureWindow::noTextureFileEvent() { int textureId = m_textureComboBox->currentIndex() - 1; m_model->removeMaterialTexture( textureId ); log_debug( "removed texture from material %d\n", textureId ); textureChangedEvent( textureId + 1 ); } void TextureWindow::newMaterialClickedEvent() { bool ok = false; QString name = QInputDialog::getText( this, tr( "Color Material", "window title" ), tr( "Enter new material name:" ), QLineEdit::Normal, QString(""), &ok ); if ( ok ) { int num = m_model->addColorMaterial( name.toUtf8() ); m_textureComboBox->insertItem( num+1, QString::fromUtf8( m_model->getTextureName(num)) ); m_textureComboBox->setCurrentIndex( num+1 ); textureChangedEvent( num+1 ); log_debug( "added %s as %d\n", (const char *) name.toUtf8(), num ); } } void TextureWindow::renameClickedEvent() { int textureId = m_textureComboBox->currentIndex() - 1; if ( textureId >= 0 ) { bool ok = false; QString name = QInputDialog::getText( this, tr( "Rename texture", "window title" ), tr( "Enter new texture name:" ), QLineEdit::Normal, QString::fromUtf8( m_model->getTextureName( textureId ) ), &ok ); if ( ok ) { m_model->setTextureName( textureId, name.toUtf8() ); m_textureComboBox->setItemText( textureId + 1, name ); } } } void TextureWindow::deleteClickedEvent() { int id = m_textureComboBox->currentIndex(); if ( id > 0 ) { m_model->deleteTexture( id - 1 ); m_textureComboBox->removeItem( id ); m_textureComboBox->setCurrentIndex( 0 ); textureChangedEvent( 0 ); } } void TextureWindow::clampSChangedEvent( int index ) { int id = m_textureComboBox->currentIndex() - 1; if ( id >= 0 ) { m_model->setTextureSClamp( id, (index == 1) ? true : false ); m_textureFrame->getTextureWidget()->setSClamp( (index == 1) ? true : false ); } } void TextureWindow::clampTChangedEvent( int index ) { int id = m_textureComboBox->currentIndex() - 1; if ( id >= 0 ) { m_model->setTextureTClamp( id, (index == 1) ? true : false ); m_textureFrame->getTextureWidget()->setTClamp( (index == 1) ? true : false ); } } /* void TextureWindow::shininessClickedEvent() { int id = (unsigned) m_textureComboBox->currentIndex() - 1; float val; if ( m_model->getTextureShininess( id, val) ) { ValueWin value; value.setLabel( "Shininess" ); value.setValue( val ); if ( value.exec() ) { val = value.getValue(); m_model->setTextureShininess( id, val ); DecalManager::getInstance()->modelUpdated( m_model ); } } else { log_error( "could not get shininess values for %d\n", id ); } } */ void TextureWindow::textureChangedEvent( int id ) { m_textureFrame->textureChangedEvent( id ); id = id - 1; if ( id >= 0 ) { m_redSlider->setEnabled( true ); m_greenSlider->setEnabled( true ); m_blueSlider->setEnabled( true ); m_alphaSlider->setEnabled( true ); m_redEdit->setEnabled( true ); m_greenEdit->setEnabled( true ); m_blueEdit->setEnabled( true ); m_alphaEdit->setEnabled( true ); m_lightingValue->setEnabled( true ); m_deleteButton->setEnabled( true ); m_renameButton->setEnabled( true ); m_sClamp->setEnabled( true ); m_tClamp->setEnabled( true ); m_fileButton->setEnabled( true ); lightValueChanged( m_lightingValue->currentIndex() ); m_sClamp->setCurrentIndex( (m_model->getTextureSClamp( id )) ? 1 : 0 ); m_tClamp->setCurrentIndex( (m_model->getTextureTClamp( id )) ? 1 : 0 ); m_textureFrame->getTextureWidget()->setSClamp( m_model->getTextureSClamp( id ) ); m_textureFrame->getTextureWidget()->setTClamp( m_model->getTextureTClamp( id ) ); } else { m_redSlider->setEnabled( false ); m_greenSlider->setEnabled( false ); m_blueSlider->setEnabled( false ); m_alphaSlider->setEnabled( false ); m_redEdit->setEnabled( false ); m_greenEdit->setEnabled( false ); m_blueEdit->setEnabled( false ); m_alphaEdit->setEnabled( false ); m_lightingValue->setEnabled( false ); m_deleteButton->setEnabled( false ); m_renameButton->setEnabled( false ); m_sClamp->setEnabled( false ); m_tClamp->setEnabled( false ); m_fileButton->setEnabled( false ); m_noFileButton->setEnabled( false ); } updateChangeButton(); } void TextureWindow::updateEvent() { int id = (unsigned) m_textureComboBox->currentIndex() - 1; float val[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; val[0] = m_redSlider->value() / 100.0; val[1] = m_greenSlider->value() / 100.0; val[2] = m_blueSlider->value() / 100.0; val[3] = m_alphaSlider->value() / 100.0; switch ( m_lightingValue->currentIndex() ) { case 0: m_model->setTextureAmbient( id, val ); break; case 1: m_model->setTextureDiffuse( id, val ); break; case 2: m_model->setTextureSpecular( id, val ); break; case 3: m_model->setTextureEmissive( id, val ); break; case 4: m_model->setTextureShininess( id, val[0] * 100.0); break; default: break; } DecalManager::getInstance()->modelUpdated( m_model ); m_textureFrame->getTextureWidget()->updateGL(); } void TextureWindow::accept() { m_model->operationComplete( tr("Texture changes").toUtf8() ); QDialog::accept(); DecalManager::getInstance()->modelUpdated( m_model ); } void TextureWindow::reject() { m_model->undoCurrent(); DecalManager::getInstance()->modelUpdated( m_model ); QDialog::reject(); } void TextureWindow::previewValueChanged( int index ) { m_textureFrame->set3d( (index == 1) ? true : false ); g_prefs( "ui_texwin_preview_index" ) = index; } void TextureWindow::lightValueChanged( int index ) { int id = (unsigned) m_textureComboBox->currentIndex() - 1; float val[4]; bool haveLighting = false; switch ( m_lightingValue->currentIndex() ) { case 0: // Ambient haveLighting = m_model->getTextureAmbient( id, val); break; case 1: // Diffuse haveLighting = m_model->getTextureDiffuse( id, val); break; case 2: // Specular haveLighting = m_model->getTextureSpecular( id, val); break; case 3: // Emissive haveLighting = m_model->getTextureEmissive( id, val); break; case 4: // Shininess haveLighting = m_model->getTextureShininess( id, val[0] ); break; default: break; } if ( m_lightingValue->currentIndex() == 4 ) { m_redLabel->setText( tr( "Shininess" ) ); m_redSlider->setMaximum( 100 ); m_redSlider->setMinimum( 0 ); m_greenLabel->hide(); m_greenSlider->hide(); m_greenEdit->hide(); m_blueLabel->hide(); m_blueSlider->hide(); m_blueEdit->hide(); m_alphaLabel->hide(); m_alphaSlider->hide(); m_alphaEdit->hide(); } else { m_redLabel->setText( tr( "Red" ) ); m_redSlider->setMaximum( 100 ); m_redSlider->setMinimum( -100 ); m_greenLabel->show(); m_greenSlider->show(); m_greenEdit->show(); m_blueLabel->show(); m_blueSlider->show(); m_blueEdit->show(); m_alphaLabel->show(); m_alphaSlider->show(); m_alphaEdit->show(); } if ( haveLighting ) { RgbaWin rgba; m_setting = true; m_redSlider->setValue( (int) (val[0] * 100) ); m_greenSlider->setValue( (int) (val[1] * 100) ); m_blueSlider->setValue( (int) (val[2] * 100) ); m_alphaSlider->setValue( (int) (val[3] * 100) ); m_setting = false; } else { log_error( "could not get lighting values for %d\n", id ); } } //------------------------------------------------------------------ // RGBA Functions //------------------------------------------------------------------ void TextureWindow::redSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_redEdit->setText( str ); } if ( !m_setting ) { updateEvent(); } } void TextureWindow::greenSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_greenEdit->setText( str ); } if ( !m_setting ) { updateEvent(); } } void TextureWindow::blueSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100.0 ); m_blueEdit->setText( str ); } if ( !m_setting ) { updateEvent(); } } void TextureWindow::alphaSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%1.02f", (float) v / 100 ); m_alphaEdit->setText( str ); } if ( !m_setting ) { updateEvent(); } } void TextureWindow::redEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_redSlider->setValue( (int) (v * 100) ); m_editing = false; } void TextureWindow::greenEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_greenSlider->setValue( (int) (v * 100) ); m_editing = false; } void TextureWindow::blueEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_blueSlider->setValue( (int) (v * 100) ); m_editing = false; } void TextureWindow::alphaEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_alphaSlider->setValue( (int) (v * 100) ); m_editing = false; } void TextureWindow::updateChangeButton() { int textureId = m_textureComboBox->currentIndex() - 1; if ( textureId >= 0 ) { if ( m_model->getMaterialType( textureId ) == Model::Material::MATTYPE_TEXTURE ) { m_fileButton->setText( tr( "Change texture...", "Change material's texture file" ) ); m_noFileButton->setEnabled( true ); } else { m_fileButton->setText( tr( "Set texture...", "Add texture file to material" ) ); m_noFileButton->setEnabled( false ); } } } mm3d-master/src/implui/texwin.h000066400000000000000000000041721324021725400167700ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TEXWIN_H #define __TEXWIN_H #include "texwin.base.h" #include class Model; class RgbaWin; class TextureWindow : public QDialog, public Ui::TextureWindowBase { Q_OBJECT public: TextureWindow( Model * model, QWidget * parent = NULL ); virtual ~TextureWindow(); public slots: void helpNowEvent(); void updateEvent(); void accept(); void reject(); void textureChangedEvent(int id ); void changeTextureFileEvent(); void noTextureFileEvent(); void newMaterialClickedEvent(); void renameClickedEvent(); void deleteClickedEvent(); void clampSChangedEvent(int index ); void clampTChangedEvent(int index ); void lightValueChanged( int ); void previewValueChanged( int ); void redSliderChanged( int ); void greenSliderChanged( int ); void blueSliderChanged( int ); void alphaSliderChanged( int ); void redEditChanged( const QString & ); void greenEditChanged( const QString & ); void blueEditChanged( const QString & ); void alphaEditChanged( const QString & ); protected: void updateChangeButton(); Model * m_model; bool m_editing; bool m_setting; }; #endif // __TEXWIN_H mm3d-master/src/implui/transformwin.cc000066400000000000000000000121651324021725400203420ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "transformwin.h" #include "textureframe.h" #include "texwidget.h" #include "model.h" #include "texture.h" #include "texmgr.h" #include "log.h" #include "rgbawin.h" #include "valuewin.h" #include "decalmgr.h" #include "msg.h" #include "3dmprefs.h" #include "helpwin.h" #include #include #include #include #include #include #include #include #include #include using std::list; using std::string; TransformWindow::TransformWindow( Model * model, QWidget * parent ) : QDialog( parent ), m_model( model ) { setupUi( this ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } TransformWindow::~TransformWindow() { } void TransformWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_transformwin.html", true ); win->show(); } void TransformWindow::close() { QDialog::hide(); } void TransformWindow::setModel( Model * m ) { m_model = m; } void TransformWindow::translateEvent() { double x = m_transX->text().toDouble(); double y = m_transY->text().toDouble(); double z = m_transZ->text().toDouble(); Matrix m; m.setTranslation( x, y, z ); applyMatrix( m, tr("Matrix Translate") ); } void TransformWindow::rotateEulerEvent() { double vec[3]; vec[0] = m_rotX->text().toDouble(); vec[1] = m_rotY->text().toDouble(); vec[2] = m_rotZ->text().toDouble(); vec[0] *= PIOVER180; // convert to radians vec[1] *= PIOVER180; // convert to radians vec[2] *= PIOVER180; // convert to radians Matrix m; m.setRotation( vec ); applyMatrix( m, tr("Matrix Rotate") ); } void TransformWindow::rotateQuaternionEvent() { double vec[3]; vec[0] = m_axisX->text().toDouble(); vec[1] = m_axisY->text().toDouble(); vec[2] = m_axisZ->text().toDouble(); double angle = m_angle->text().toDouble(); angle = angle * PIOVER180; // convert to radians Matrix m; m.setRotationOnAxis( vec, angle ); applyMatrix( m, tr("Matrix Rotate On Axis") ); } void TransformWindow::scaleEvent() { double x = m_scaleX->text().toDouble(); double y = m_scaleY->text().toDouble(); double z = m_scaleZ->text().toDouble(); Matrix m; m.set( 0, 0, x ); m.set( 1, 1, y ); m.set( 2, 2, z ); applyMatrix( m, tr("Matrix Scale") ); } void TransformWindow::matrixEvent() { Matrix m; m.set( 0, 0, m_00->text().toDouble() ); m.set( 0, 1, m_01->text().toDouble() ); m.set( 0, 2, m_02->text().toDouble() ); m.set( 0, 3, m_03->text().toDouble() ); m.set( 1, 0, m_10->text().toDouble() ); m.set( 1, 1, m_11->text().toDouble() ); m.set( 1, 2, m_12->text().toDouble() ); m.set( 1, 3, m_13->text().toDouble() ); m.set( 2, 0, m_20->text().toDouble() ); m.set( 2, 1, m_21->text().toDouble() ); m.set( 2, 2, m_22->text().toDouble() ); m.set( 2, 3, m_23->text().toDouble() ); m.set( 3, 0, m_30->text().toDouble() ); m.set( 3, 1, m_31->text().toDouble() ); m.set( 3, 2, m_32->text().toDouble() ); m.set( 3, 3, m_33->text().toDouble() ); applyMatrix( m, tr("Apply Matrix") ); } bool TransformWindow::matrixIsUndoable( const Matrix & m ) { if ( fabs( m.getDeterminant() ) >= 0.0006 ) return true; else return false; } bool TransformWindow::warnNoUndo( bool undoable ) { if ( !undoable ) { if ( QMessageBox::warning( NULL, tr("Transform Cannot Be Undone", "window title"), tr("This transformation cannot be undone.") + QString("\n") + tr("Are you sure you wish to continue?" ), tr("Apply Transformation", "button" ), tr("Cancel Transformation", "button" ) ) == 0 ) return true; else return false; } return true; } void TransformWindow::applyMatrix( const Matrix & m, const QString & action ) { bool undoable = matrixIsUndoable( m ); if ( warnNoUndo( undoable ) ) { Model::OperationScopeE scope = (m_scope->currentIndex() == 0) ? Model::OS_Selected : Model::OS_Global; m_model->applyMatrix( m, scope, true, undoable ); m_model->operationComplete( action.toUtf8() ); DecalManager::getInstance()->modelUpdated( m_model ); } } mm3d-master/src/implui/transformwin.h000066400000000000000000000033011324021725400201740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TRANSFORMWIN_H #define __TRANSFORMWIN_H #include "transformwin.base.h" #include "glmath.h" #include class Model; class RgbaWin; class TransformWindow : public QDialog, public Ui::TransformWindowBase { Q_OBJECT public: TransformWindow( Model * model, QWidget * parent = NULL ); virtual ~TransformWindow(); bool matrixIsUndoable( const Matrix & m ); bool warnNoUndo( bool undoable ); public slots: // Transform window events void translateEvent(); void rotateEulerEvent(); void rotateQuaternionEvent(); void scaleEvent(); void matrixEvent(); void setModel( Model * m ); void helpNowEvent(); void close(); protected: void applyMatrix( const Matrix & m, const QString & action ); Model * m_model; }; #endif // __TRANSFORMWIN_H mm3d-master/src/implui/transimp.cc000066400000000000000000000022101324021725400174340ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "transimp.h" #include #include "translate.h" std::string _qt_translate( const char * str ) { return std::string( (const char *) qApp->translate( "LowLevel", str ).toUtf8() ); } void transimp_install_translator() { transll_install_handler( _qt_translate ); } mm3d-master/src/implui/transimp.h000066400000000000000000000017031324021725400173040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TRANSIMP_H #define __TRANSIMP_H void transimp_install_translator(); #endif // __TRANSIMP_H mm3d-master/src/implui/valuewin.cc000066400000000000000000000044751324021725400174500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "valuewin.h" #include "helpwin.h" #include "log.h" #include #include #include #include #include #include ValueWin::ValueWin( QWidget * parent, bool modal, Qt::WindowFlags flags ) : QDialog( parent, flags ), m_editing( false ) { setupUi( this ); setModal( modal ); m_valueEdit->setText( QString( "0" ) ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); } ValueWin::~ValueWin() { } void ValueWin::helpNowEvent() { showHelp(); } void ValueWin::showHelp() { HelpWin * win = new HelpWin( "olh_valuewin.html", true ); win->show(); } void ValueWin::setLabel( const char * newLabel ) { if ( newLabel ) { setWindowTitle( QString( newLabel ) ); QString str; str.sprintf( "%s", newLabel ); m_propertyLabel->setText( str ); } } float ValueWin::getValue() { return (float) m_valueSlider->value(); } void ValueWin::setValue( const float & v ) { m_valueSlider->setValue( (int) v ); } void ValueWin::valueSliderChanged( int v ) { if ( ! m_editing ) { QString str; str.sprintf( "%d", v ); m_valueEdit->setText( str ); } } void ValueWin::valueEditChanged( const QString & str ) { m_editing = true; float v = str.toDouble(); m_valueSlider->setValue( (int) v ); m_editing = false; } mm3d-master/src/implui/valuewin.h000066400000000000000000000033351324021725400173040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __VALUEWIN_H #define __VALUEWIN_H #include "valuewin.base.h" #include class ValueWin : public QDialog, public Ui::ValueWinBase { Q_OBJECT public: ValueWin( QWidget * parent = NULL, bool modal = true, Qt::WindowFlags flags = 0 ); virtual ~ValueWin(); void setLabel( const char * newLabel ); float getValue(); void setValue( const float & v ); public slots: void helpNowEvent(); virtual void valueEditChanged( const QString & ); virtual void valueSliderChanged( int ); protected: virtual void showHelp(); // We don't want to update the edit box if the user is typing in it // So we set this to true when editing. When we update the slider, // our slot will check this value. If false, it will update the edit box bool m_editing; }; #endif // __VALUEWIN_H mm3d-master/src/implui/viewpanel.cc000066400000000000000000000227121324021725400176020ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "viewpanel.h" #include "mview.h" #include "toolbox.h" #include "model.h" #include "log.h" #include "msg.h" #include "modelviewport.h" #include "3dmprefs.h" #include #include ViewPanel::ViewPanel( Toolbox * toolbox, QWidget * parent ) : QWidget( parent ), m_model( NULL ), m_viewCount( 4 ), m_tall( false ), m_toolbox( toolbox ) { if ( g_prefs.exists( "ui_viewport_count" ) ) { m_viewCount = g_prefs( "ui_viewport_count" ).intValue(); if ( m_viewCount < 1 || m_viewCount > 9 ) { m_viewCount = 4; } } if ( g_prefs.exists( "ui_viewport_tall" ) ) { int tall = g_prefs( "ui_viewport_tall" ).intValue(); m_tall = ( tall != 0 ); } makeViews(); for ( unsigned s = 0; s < VIEWPORT_STATE_MAX; s++ ) { m_viewState[s].rotation[0] = -1000.0; } show(); } ViewPanel::~ViewPanel() { log_debug( "deleting view panel\n" ); } void ViewPanel::freeTextures() { for ( unsigned t = 0; t < m_viewCount; t++ ) { m_modelView[t]->freeTextures(); } } void ViewPanel::setModel( Model * model ) { if ( m_model != NULL && model != NULL ) { model->setPerspectiveDrawMode(m_model->getPerspectiveDrawMode()); model->setCanvasDrawMode(m_model->getCanvasDrawMode()); } for ( unsigned t = 0; t < m_viewCount; t++ ) { m_modelView[t]->setModel( model ); } m_model = model; } void ViewPanel::modelUpdatedEvent() { for ( unsigned t = 0; t < m_viewCount; t++ ) { m_modelView[t]->updateView(); } } void ViewPanel::frameArea( double x1, double y1, double z1, double x2, double y2, double z2 ) { for ( unsigned t = 0; t < m_viewCount; t++ ) { m_modelView[t]->frameArea( x1, y1, z1, x2, y2, z2 ); } } void ViewPanel::wireframeEvent() { m_model->setPerspectiveDrawMode( ModelViewport::ViewWireframe ); modelUpdatedEvent(); } void ViewPanel::flatEvent() { m_model->setPerspectiveDrawMode( ModelViewport::ViewFlat ); modelUpdatedEvent(); } void ViewPanel::smoothEvent() { m_model->setPerspectiveDrawMode( ModelViewport::ViewSmooth ); modelUpdatedEvent(); } void ViewPanel::textureEvent() { m_model->setPerspectiveDrawMode( ModelViewport::ViewTexture ); modelUpdatedEvent(); } void ViewPanel::alphaEvent() { m_model->setPerspectiveDrawMode( ModelViewport::ViewAlpha ); modelUpdatedEvent(); } void ViewPanel::canvasWireframeEvent() { m_model->setCanvasDrawMode( ModelViewport::ViewWireframe ); modelUpdatedEvent(); } void ViewPanel::canvasFlatEvent() { m_model->setCanvasDrawMode( ModelViewport::ViewFlat ); modelUpdatedEvent(); } void ViewPanel::canvasSmoothEvent() { m_model->setCanvasDrawMode( ModelViewport::ViewSmooth ); modelUpdatedEvent(); } void ViewPanel::canvasTextureEvent() { m_model->setCanvasDrawMode( ModelViewport::ViewTexture ); modelUpdatedEvent(); } void ViewPanel::canvasAlphaEvent() { m_model->setCanvasDrawMode( ModelViewport::ViewAlpha ); modelUpdatedEvent(); } void ViewPanel::makeViews() { g_prefs( "ui_viewport_count" ) = (int) m_viewCount; g_prefs( "ui_viewport_tall" ) = (int) m_tall ? 1 : 0; int width = 3; int height = 3; m_gridLayout = new QGridLayout( this ); m_gridLayout->setSpacing(0); m_gridLayout->setMargin(0); switch ( m_viewCount ) { case 1: width = 1; height = 1; break; case 2: if ( m_tall ) { width = 1; height = 2; } else { width = 2; height = 1; } break; case 4: width = 2; height = 2; break; case 6: if ( m_tall ) { width = 2; height = 3; } else { width = 3; height = 2; } break; default: width = 3; height = 3; break; } for ( unsigned t = 0; t < m_viewCount; t++ ) { m_modelView[t] = new ModelView( m_toolbox, this ); connect( m_modelView[t]->getModelViewport(), SIGNAL(viewportSaveState(int, const ModelViewport::ViewStateT & )), this, SLOT(viewportSaveStateEvent(int, const ModelViewport::ViewStateT &)) ); connect( m_modelView[t]->getModelViewport(), SIGNAL(viewportRecallState(int)), this, SLOT(viewportRecallStateEvent(int)) ); m_gridLayout->addWidget( m_modelView[t], t / width, t % width ); } setModel( m_model ); setDefaultViewDirections(); if ( m_model ) { double x1, y1, z1, x2, y2, z2; if ( m_model->getBoundingRegion( &x1, &y1, &z1, &x2, &y2, &z2 ) ) { frameArea( x1, y1, z1, x2, y2, z2 ); } } } void ViewPanel::deleteViews() { for ( unsigned t = 0; t < m_viewCount; t++ ) { delete m_modelView[t]; } delete m_gridLayout; } void ViewPanel::setDefaultViewDirections() { switch ( m_viewCount ) { case 1: m_modelView[0]->setViewDirection( ModelViewport::ViewPerspective ); break; case 2: m_modelView[0]->setViewDirection( ModelViewport::ViewOrtho ); m_modelView[1]->setViewDirection( ModelViewport::ViewPerspective ); break; case 4: m_modelView[0]->setViewDirection( ModelViewport::ViewFront ); m_modelView[1]->setViewDirection( ModelViewport::ViewLeft ); m_modelView[2]->setViewDirection( ModelViewport::ViewTop ); m_modelView[3]->setViewDirection( ModelViewport::ViewPerspective ); break; case 6: if ( m_tall ) { m_modelView[0]->setViewDirection( ModelViewport::ViewFront ); m_modelView[1]->setViewDirection( ModelViewport::ViewBack ); m_modelView[2]->setViewDirection( ModelViewport::ViewLeft ); m_modelView[3]->setViewDirection( ModelViewport::ViewRight ); m_modelView[4]->setViewDirection( ModelViewport::ViewTop ); m_modelView[5]->setViewDirection( ModelViewport::ViewPerspective ); } else { m_modelView[0]->setViewDirection( ModelViewport::ViewFront ); m_modelView[1]->setViewDirection( ModelViewport::ViewBack ); m_modelView[2]->setViewDirection( ModelViewport::ViewTop ); m_modelView[3]->setViewDirection( ModelViewport::ViewLeft ); m_modelView[4]->setViewDirection( ModelViewport::ViewRight ); m_modelView[5]->setViewDirection( ModelViewport::ViewPerspective ); } break; default: m_modelView[0]->setViewDirection( ModelViewport::ViewFront ); m_modelView[1]->setViewDirection( ModelViewport::ViewBack ); m_modelView[4]->setViewDirection( ModelViewport::ViewRight ); m_modelView[2]->setViewDirection( ModelViewport::ViewTop ); m_modelView[5]->setViewDirection( ModelViewport::ViewBottom ); m_modelView[3]->setViewDirection( ModelViewport::ViewLeft ); m_modelView[6]->setViewDirection( ModelViewport::ViewOrtho ); m_modelView[7]->setViewDirection( ModelViewport::ViewOrtho ); m_modelView[8]->setViewDirection( ModelViewport::ViewPerspective ); break; } } void ViewPanel::view1() { hide(); deleteViews(); m_viewCount = 1; makeViews(); show(); } void ViewPanel::view1x2() { hide(); deleteViews(); m_viewCount = 2; m_tall = true; makeViews(); show(); } void ViewPanel::view2x1() { hide(); deleteViews(); m_viewCount = 2; m_tall = false; makeViews(); show(); } void ViewPanel::view2x2() { hide(); deleteViews(); m_viewCount = 4; makeViews(); show(); } void ViewPanel::view2x3() { hide(); deleteViews(); m_viewCount = 6; m_tall = true; makeViews(); show(); } void ViewPanel::view3x2() { hide(); deleteViews(); m_viewCount = 6; m_tall = false; makeViews(); show(); } void ViewPanel::view3x3() { hide(); deleteViews(); m_viewCount = 9; makeViews(); show(); } void ViewPanel::viewportSaveStateEvent( int slot, const ModelViewport::ViewStateT & viewState ) { if ( slot >= 0 && slot < VIEWPORT_STATE_MAX ) { m_viewState[slot] = viewState; } } void ViewPanel::viewportRecallStateEvent( int slot ) { if ( slot >= 0 && slot < VIEWPORT_STATE_MAX && m_viewState[slot].rotation[0] > -900.0 ) { for ( unsigned v = 0; v < m_viewCount; v++ ) { ModelViewport * m = m_modelView[v]->getModelViewport(); if ( m->hasFocus() ) { m_modelView[v]->setViewDirection( m_viewState[slot].direction ); m->setViewState( m_viewState[slot] ); } } } } mm3d-master/src/implui/viewpanel.h000066400000000000000000000051071324021725400174430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __VIEWPANEL_H #define __VIEWPANEL_H #include #include #include "modelviewport.h" class QGridLayout; class ModelView; class Model; class Toolbox; class ViewPanel : public QWidget { Q_OBJECT public: enum { VIEWPORT_STATE_MAX = 9 }; ViewPanel( Toolbox * toolbox, QWidget * parent = NULL ); virtual ~ViewPanel(); void freeTextures(); void setModel( Model * model ); void frameArea( double x1, double y1, double z1, double x2, double y2, double z2 ); unsigned getModelViewCount() { return m_viewCount; }; ModelView * getModelView( unsigned index ) { return (index < m_viewCount) ? m_modelView[index] : NULL; }; public slots: void modelUpdatedEvent(); void wireframeEvent(); void flatEvent(); void smoothEvent(); void textureEvent(); void alphaEvent(); void canvasWireframeEvent(); void canvasFlatEvent(); void canvasSmoothEvent(); void canvasTextureEvent(); void canvasAlphaEvent(); void view1(); void view1x2(); void view2x1(); void view2x2(); void view2x3(); void view3x2(); void view3x3(); public slots: void viewportSaveStateEvent(int, const ModelViewport::ViewStateT &); void viewportRecallStateEvent(int); protected: void deleteViews(); void makeViews(); void setDefaultViewDirections(); Model * m_model; QGridLayout * m_gridLayout; ModelView * m_modelView[9]; ModelViewport::ViewStateT m_viewState[ VIEWPORT_STATE_MAX ]; unsigned m_viewCount; bool m_tall; Toolbox * m_toolbox; }; #endif // __VIEWPANEL_H mm3d-master/src/implui/viewportsettings.cc000066400000000000000000000056411324021725400212520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "viewportsettings.h" #include "helpwin.h" #include "3dmprefs.h" #include #include #include ViewportSettings::ViewportSettings( QWidget * parent ) : QDialog( parent ) { setAttribute( Qt::WA_DeleteOnClose ); setupUi( this ); setModal( true ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); QString temp; m_gridUnit->setText( QString( g_prefs( "ui_grid_inc" ).stringValue().c_str() ) ); m_3dGridUnit->setText( QString( g_prefs( "ui_3dgrid_inc" ).stringValue().c_str() ) ); m_3dGridLines->setText( QString( g_prefs( "ui_3dgrid_count" ).stringValue().c_str() ) ); switch ( g_prefs( "ui_grid_mode" ).intValue() ) { default: case 0: m_binaryGrid->setChecked( true ); break; case 1: m_decimalGrid->setChecked( true ); break; case 2: m_fixedGrid->setChecked( true ); break; } m_3dXY->setChecked( g_prefs( "ui_3dgrid_xy" ).intValue() != 0 ); m_3dXZ->setChecked( g_prefs( "ui_3dgrid_xz" ).intValue() != 0 ); m_3dYZ->setChecked( g_prefs( "ui_3dgrid_yz" ).intValue() != 0 ); } ViewportSettings::~ViewportSettings() { } void ViewportSettings::accept() { g_prefs( "ui_grid_inc" ) = (const char *) m_gridUnit->text().toLatin1(); g_prefs( "ui_3dgrid_inc" ) = (const char *) m_3dGridUnit->text().toLatin1(); g_prefs( "ui_3dgrid_count" ) = (const char *) m_3dGridLines->text().toLatin1(); int grid_mode = 0; if ( m_decimalGrid->isChecked() ) grid_mode = 1; else if (m_fixedGrid->isChecked() ) grid_mode = 2; g_prefs( "ui_grid_mode" ) = grid_mode; g_prefs( "ui_3dgrid_xy" ) = m_3dXY->isChecked() ? 1 : 0; g_prefs( "ui_3dgrid_xz" ) = m_3dXZ->isChecked() ? 1 : 0; g_prefs( "ui_3dgrid_yz" ) = m_3dYZ->isChecked() ? 1 : 0; QDialog::accept(); } void ViewportSettings::helpNowEvent() { HelpWin * win = new HelpWin( "olh_viewportsettings.html", true ); win->show(); } mm3d-master/src/implui/viewportsettings.h000066400000000000000000000024021324021725400211040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __VIEWPORTSETTINGS_H #define __VIEWPORTSETTINGS_H #include "viewportsettings.base.h" #include class ViewportSettings : public QDialog, public Ui::ViewportSettingsBase { Q_OBJECT public: ViewportSettings( QWidget * parent = NULL ); virtual ~ViewportSettings(); public slots: void helpNowEvent(); void accept(); private: }; #endif // __VIEWPORTSETTINGS_H mm3d-master/src/implui/viewwin.cc000066400000000000000000002327121324021725400173030ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "pluginmgr.h" #include "viewwin.h" #include "viewpanel.h" #include "model.h" #include "tool.h" #include "toolbox.h" #include "cmdmgr.h" #include "viewportsettings.h" #include "groupclean.h" #include "groupwin.h" #include "texwin.h" #include "texturecoord.h" #include "painttexturewin.h" #include "log.h" #include "decalmgr.h" #include "msg.h" #include "statusbar.h" #include "modelstatus.h" #include "filtermgr.h" #include "misc.h" #include "helpwin.h" #include "licensewin.h" #include "aboutwin.h" #include "animsetwin.h" #include "animexportwin.h" #include "animwin.h" #include "animwidget.h" #include "metawin.h" #include "3dmprefs.h" #include "stdcmds.h" #include "pluginwin.h" #include "backgroundwin.h" #include "mergewin.h" #include "misc.h" #include "version.h" #include "texmgr.h" #include "sysconf.h" #include "contextpanel.h" #include "boolpanel.h" #include "projectionwin.h" #include "transformwin.h" #include "keycfg.h" #include "qtmain.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "errorobj.h" #include "luascript.h" #include "luaif.h" #include "pixmap/mm3dlogo-32x32.xpm" #include #include #include using std::list; using std::string; const char DOCK_FILENAME[] = "dock.dat"; const int DOCK_VERSION = 1; //using namespace QIconSet; typedef QAction * QActionPtr; typedef ::Tool * ToolPtr; typedef std::list< ViewWindow *> ViewWindowList; static ViewWindowList _winList; static bool _shuttingDown = false; CommandWidget::CommandWidget( QObject * parent, Model * model, bool * canEdit, Command * cmd, int index ) : QObject( parent ), m_model( model ), m_canEdit( canEdit ), m_cmd( cmd ), m_index( index ) { } CommandWidget::~CommandWidget() { } void CommandWidget::setModel( Model * m ) { m_model = m; } void CommandWidget::activateCommand( bool ) { if ( !(*m_canEdit) ) { model_status( m_model, StatusError, STATUSTIME_LONG, tr("You are in animation mode, but there are no animations").toUtf8() ); return; } if ( m_cmd->activated( m_index, m_model ) ) { m_model->operationComplete( qApp->translate( "Command", (m_cmd)->getName( m_index ) ).toUtf8() ); DecalManager * mgr = DecalManager::getInstance(); mgr->modelUpdated( m_model ); } } bool ViewWindow::closeAllWindows() { bool noPrompt = true; bool doSave = false; std::list::iterator it; for ( it = _winList.begin(); noPrompt == true && it != _winList.end(); it++ ) { noPrompt = (*it)->getSaved(); } #ifndef CODE_DEBUG if ( noPrompt == false ) { char response = msg_warning_prompt( (const char *) tr("Some models are unsaved. Save before exiting?").toUtf8() ); if ( response == 'C' ) { return false; } if ( response == 'Y' ) { doSave = true; } } #endif // CODE_DEBUG bool abortQuit = false; for ( it = _winList.begin(); !abortQuit && it != _winList.end(); it++ ) { ViewWindow * win = (*it); if ( doSave && win->getSaved() == false ) { win->raise(); win->setAbortQuit( false ); win->saveModelEvent(); abortQuit = win->getAbortQuit(); } } if ( !abortQuit ) { while ( !_winList.empty() ) { ViewWindow * win = _winList.front(); win->hide(); win->deleteLater(); _winList.pop_front(); } } if ( abortQuit ) { return false; } else { return true; } } // open model in an existing window that doesn't have a model open or open a new window. bool ViewWindow::openModelInEmptyWindow( const char * filename ) { QWindow *window = NULL; std::list::iterator it; for ( it = _winList.begin(); it != _winList.end(); it++ ) { if ( !(*it)->emptyWindow() ) { continue; } if ( !(*it)->openModelInWindow( filename ) ) { return false; } // Unminimize and move window to foreground window = (*it)->windowHandle(); window->show(); window->raise(); window->requestActivate(); break; } if ( !window ) { return ViewWindow::openModel( filename ); } return false; } class MainWidget : public QWidget { public: MainWidget( QWidget * parent = NULL ); virtual ~MainWidget() {}; void addWidgetToLayout( QWidget * w ); protected: QVBoxLayout * m_layout; }; MainWidget::MainWidget( QWidget * parent ) : QWidget( parent ) { m_layout = new QVBoxLayout( this ); m_layout->setMargin(2); m_layout->setSpacing(2); } void MainWidget::addWidgetToLayout( QWidget * w ) { m_layout->addWidget( w ); } ViewWindow::ViewWindow( Model * model, QWidget * parent ) : QMainWindow( parent ), m_model( model ), m_animWin( NULL ), m_toolbox( NULL ), m_toolList( NULL ), m_toolButtons( NULL ), m_last( NULL ), m_currentTool( NULL ), m_canEdit( true ) { m_model->setUndoEnabled( false ); setAttribute( Qt::WA_DeleteOnClose ); _winList.push_back( this ); setWindowIcon( QPixmap((const char **) mm3dlogo_32x32_xpm) ); setWindowIconText( QString("Misfit Model 3D") ); QShortcut * help = new QShortcut( QKeySequence( tr("F1", "Help Shortcut")), this ); connect( help, SIGNAL(activated()), this, SLOT(helpNowEvent()) ); updateCaption(); m_toolbox = new Toolbox(); MainWidget * mainWidget = new MainWidget( this ); m_viewPanel = new ViewPanel( m_toolbox, mainWidget ); mainWidget->addWidgetToLayout( m_viewPanel ); m_statusBar = new StatusBar( m_model, mainWidget ); mainWidget->addWidgetToLayout( m_statusBar ); m_statusBar->setText( tr( "Press F1 for help using any window" ).toUtf8() ); m_statusBar->setMaximumHeight( 30 ); m_animWin = new AnimWindow( m_model, false, this ); m_animWin->setObjectName( "mainwin_animwin" ); m_animWidget = m_animWin->getAnimWidget(); addDockWidget( Qt::BottomDockWidgetArea, m_animWin ); connect( m_animWin, SIGNAL(animWindowClosed()), this, SLOT(animationModeOff()) ); connect( m_animWidget, SIGNAL(animWindowClosed()), this, SLOT(animationModeOff()) ); connect( m_animWidget, SIGNAL(animInvalid()), this, SLOT(editDisableEvent()) ); connect( m_animWidget, SIGNAL(animValid()), this, SLOT(editEnableEvent()) ); m_contextPanel = new ContextPanel( this, m_viewPanel, this ); m_contextPanel->setObjectName( "mainwin_properties" ); m_contextPanel->setWindowTitle( tr( "Properties" ) ); connect( this, SIGNAL(modelChanged(Model*)), m_contextPanel, SLOT(setModel(Model*))); addDockWidget( Qt::RightDockWidgetArea, m_contextPanel ); m_boolPanel = new BoolPanel( m_model, this, m_viewPanel ); m_boolPanel->setObjectName( "mainwin_boolwin" ); connect( this, SIGNAL(modelChanged(Model*)), m_boolPanel, SLOT(setModel(Model*))); m_projectionWin = new ProjectionWin( m_model, this, m_viewPanel ); connect( this, SIGNAL(modelChanged(Model*)), m_projectionWin, SLOT(setModel(Model*))); m_textureCoordWin = new TextureCoord( m_model ); connect( this, SIGNAL(modelChanged(Model*)), m_textureCoordWin, SLOT(setModel(Model*))); m_transformWin = new TransformWindow( m_model, this ); connect( this, SIGNAL(modelChanged(Model*)), m_transformWin, SLOT(setModel(Model*))); addDockWidget( Qt::RightDockWidgetArea, m_boolPanel ); setModel( m_model ); tabifyDockWidget( m_contextPanel, m_boolPanel ); setCentralWidget( mainWidget ); m_mruMenu = new QMenu( this ); m_scriptMruMenu = new QMenu( this ); connect( m_mruMenu, SIGNAL(aboutToShow()), this, SLOT(fillMruMenu()) ); connect( m_mruMenu, SIGNAL(triggered(QAction*)), this, SLOT(openMru(QAction*)) ); connect( m_scriptMruMenu, SIGNAL(aboutToShow()), this, SLOT(fillScriptMruMenu()) ); connect( m_scriptMruMenu, SIGNAL(triggered(QAction*)), this, SLOT(openScriptMru(QAction*)) ); m_fileMenu = new QMenu( this ); m_fileMenu->addAction( tr("New", "File|New"), this, SLOT(newModelEvent()), g_keyConfig.getKey( "viewwin_file_new" ) ); m_fileMenu->addAction( tr("Open...", "File|Open"), this, SLOT(openModelEvent()), g_keyConfig.getKey( "viewwin_file_open" ) ); m_fileMenu->addAction( tr("Save", "File|Save"), this, SLOT(saveModelEvent()), g_keyConfig.getKey( "viewwin_file_save" ) ); m_fileMenu->addAction( tr("Save As...", "File|Save As"), this, SLOT(saveModelAsEvent()), g_keyConfig.getKey( "viewwin_file_save_as" ) ); m_fileMenu->addAction( tr("Export...", "File|Export"), this, SLOT(exportModelEvent()), g_keyConfig.getKey( "viewwin_file_export" ) ); m_fileMenu->addAction( tr("Export Selected...", "File|Export Selected"), this, SLOT(exportSelectedEvent()), g_keyConfig.getKey( "viewwin_file_export_selected" ) ); #ifdef HAVE_LUALIB m_fileMenu->addAction( tr("Run Script...", "File|Run Script"), this, SLOT(scriptEvent()), g_keyConfig.getKey( "viewwin_file_run_script" ) ); m_scriptMruMenu->setTitle( tr("Recent Scripts", "File|Recent Script") ); m_fileMenu->addMenu( m_scriptMruMenu ); #endif // HAVE_LUALIB m_fileMenu->addSeparator(); m_mruMenu->setTitle( tr("Recent Models", "File|Recent Models") ); m_fileMenu->addMenu( m_mruMenu ); m_fileMenu->addSeparator(); m_fileMenu->addAction( tr("Plugins...", "File|Plugins"), this, SLOT(pluginWindowEvent()), g_keyConfig.getKey( "viewwin_file_plugins" ) ); m_fileMenu->addSeparator(); m_fileMenu->addAction( tr("Close", "File|Close"), this, SLOT(close()), g_keyConfig.getKey( "viewwin_file_close" ) ); m_fileMenu->addAction( tr("Quit", "File|Quit"), this, SLOT(quitEvent()), g_keyConfig.getKey( "viewwin_file_quit" ) ); m_renderMenu = new QMenu( this ); QActionGroup * group; // Bones group group = new QActionGroup( this ); m_hideJointsItem = m_renderMenu->addAction( tr("Hide Joints", "View|Hide Joints"), this, SLOT(boneJointHide()), g_keyConfig.getKey( "viewwin_view_render_joints_hide" ) ); m_drawJointLinesItem = m_renderMenu->addAction( tr("Draw Joint Lines", "View|Draw Joint Lines"), this, SLOT(boneJointLines()), g_keyConfig.getKey( "viewwin_view_render_joints_lines" ) ); m_drawJointBonesItem = m_renderMenu->addAction( tr("Draw Joint Bones", "View|Draw Joint Bones"), this, SLOT(boneJointBones()), g_keyConfig.getKey( "viewwin_view_render_joints_bones" ) ); m_hideJointsItem->setCheckable( true ); m_drawJointLinesItem->setCheckable( true ); m_drawJointBonesItem->setCheckable( true ); group->addAction( m_hideJointsItem ); group->addAction( m_drawJointLinesItem ); group->addAction( m_drawJointBonesItem ); g_prefs.setDefault( "ui_draw_joints", (int) Model::JOINTMODE_BONES ); if ( g_prefs( "ui_draw_joints" ).intValue() == (int) Model::JOINTMODE_BONES ) m_drawJointBonesItem->setChecked( true ); else m_drawJointBonesItem->setChecked( true ); m_renderMenu->addSeparator(); // Projection group group = new QActionGroup( this ); m_renderProjections = m_renderMenu->addAction( tr("Draw Texture Projections", "View|Draw Texture Projections"), this, SLOT(renderProjections()), g_keyConfig.getKey( "viewwin_view_render_projections_show" ) ); m_noRenderProjections = m_renderMenu->addAction( tr("Hide Texture Projections", "View|Hide Texture Projections"), this, SLOT(noRenderProjections()), g_keyConfig.getKey( "viewwin_view_render_projections_hide" ) ); m_renderProjections->setCheckable( true ); m_noRenderProjections->setCheckable( true ); group->addAction( m_renderProjections ); group->addAction( m_noRenderProjections ); m_renderProjections->setChecked( true ); m_renderMenu->addSeparator(); // Bad texture group group = new QActionGroup( this ); m_renderBadItem = m_renderMenu->addAction( tr("Use Red Error Texture", "View|Use Red Error Texture"), this, SLOT(renderBadEvent()), g_keyConfig.getKey( "viewwin_view_render_badtex_red" ) ); m_noRenderBadItem = m_renderMenu->addAction( tr("Use Blank Error Texture", "View|Use Blank Error Texture"), this, SLOT(noRenderBadEvent()), g_keyConfig.getKey( "viewwin_view_render_badtex_blank" ) ); m_renderBadItem->setCheckable( true ); m_noRenderBadItem->setCheckable( true ); group->addAction( m_renderBadItem ); group->addAction( m_noRenderBadItem ); g_prefs.setDefault( "ui_render_bad_textures", 1 ); if ( g_prefs( "ui_render_bad_textures" ).intValue() != 0 ) m_renderBadItem->setChecked( true ); else m_noRenderBadItem->setChecked( true ); m_renderMenu->addSeparator(); // 3D Lines group group = new QActionGroup( this ); m_renderSelectionItem = m_renderMenu->addAction( tr("Render 3D Lines", "View|Render 3D Lines"), this, SLOT(renderSelectionEvent()), g_keyConfig.getKey( "viewwin_view_render_3d_lines_show" ) ); m_noRenderSelectionItem = m_renderMenu->addAction( tr("Hide 3D Lines", "View|Hide 3D Lines"), this, SLOT(noRenderSelectionEvent()), g_keyConfig.getKey( "viewwin_view_render_3d_lines_hide" ) ); m_renderSelectionItem->setCheckable( true ); m_noRenderSelectionItem->setCheckable( true ); group->addAction( m_renderSelectionItem ); group->addAction( m_noRenderSelectionItem ); g_prefs.setDefault( "ui_render_3d_selections", 0 ); if ( g_prefs( "ui_render_3d_selections" ).intValue() != 0 ) m_renderSelectionItem->setChecked( true ); else m_noRenderSelectionItem->setChecked( true ); m_renderMenu->addSeparator(); // Backfacing poly group group = new QActionGroup( this ); m_renderBackface = m_renderMenu->addAction( tr("Draw Back-facing Triangles", "View|Draw Back-facing Triangles"), this, SLOT(renderBackface()), g_keyConfig.getKey( "viewwin_view_render_backface_show" ) ); m_noRenderBackface = m_renderMenu->addAction( tr("Hide Back-facing Triangles", "View|Hide Back-facing Triangles"), this, SLOT(noRenderBackface()), g_keyConfig.getKey( "viewwin_view_render_backface_hide" ) ); m_renderBackface->setCheckable( true ); m_noRenderBackface->setCheckable( true ); group->addAction( m_renderBackface ); group->addAction( m_noRenderBackface ); g_prefs.setDefault( "ui_render_backface_cull", 0 ); if ( g_prefs( "ui_render_backface_cull" ).intValue() == 0 ) m_renderBackface->setChecked( true ); else m_noRenderBackface->setChecked( true ); m_viewMenu = new QMenu( this ); m_viewMenu->addAction( tr( "Frame All", "View|Frame"), this, SLOT(frameAllEvent()), g_keyConfig.getKey( "viewwin_view_frame_all" ) ); m_viewMenu->addAction( tr( "Frame Selected", "View|Frame"), this, SLOT(frameSelectedEvent()), g_keyConfig.getKey( "viewwin_view_frame_selected" ) ); m_viewMenu->addSeparator(); m_showContext = m_viewMenu->addAction( tr("Show Properties", "View|Show Properties"), this, SLOT(showContextEvent()), g_keyConfig.getKey( "viewwin_view_show_properties" ) ); connect( m_contextPanel, SIGNAL(panelHidden()), this, SLOT(contextPanelHidden()) ); m_renderMenu->setTitle( tr( "Render Options", "View|Render Options") ); m_viewMenu->addMenu( m_renderMenu ); m_viewMenu->addSeparator(); // 3D View group group = new QActionGroup(this); m_3dWire = group->addAction( m_viewMenu->addAction( tr( "3D Wireframe", "View|3D"), m_viewPanel, SLOT(wireframeEvent()), g_keyConfig.getKey( "viewwin_view_3d_wireframe" ) ) ); m_3dFlat = group->addAction( m_viewMenu->addAction( tr( "3D Flat", "View|3D"), m_viewPanel, SLOT(flatEvent()), g_keyConfig.getKey( "viewwin_view_3d_flat" ) ) ); m_3dSmooth = group->addAction( m_viewMenu->addAction( tr( "3D Smooth", "View|3D"), m_viewPanel, SLOT(smoothEvent()), g_keyConfig.getKey( "viewwin_view_3d_smooth" ) ) ); m_3dTexture = group->addAction( m_viewMenu->addAction( tr( "3D Texture", "View|3D"), m_viewPanel, SLOT(textureEvent()), g_keyConfig.getKey( "viewwin_view_3d_textured" ) ) ); m_3dAlpha = group->addAction( m_viewMenu->addAction( tr( "3D Alpha Blend", "View|3D"), m_viewPanel, SLOT(alphaEvent()), g_keyConfig.getKey( "viewwin_view_3d_alpha" ) ) ); m_viewMenu->addSeparator(); // Canvas Group group = new QActionGroup(this); m_canvasWire = group->addAction( m_viewMenu->addAction( tr( "Canvas Wireframe", "View|Canvas"), m_viewPanel, SLOT(canvasWireframeEvent()), g_keyConfig.getKey( "viewwin_view_ortho_wireframe" ) ) ); m_canvasFlat = group->addAction( m_viewMenu->addAction( tr( "Canvas Flat", "View|Canvas"), m_viewPanel, SLOT(canvasFlatEvent()), g_keyConfig.getKey( "viewwin_view_ortho_flat" ) ) ); m_canvasSmooth = group->addAction( m_viewMenu->addAction( tr( "Canvas Smooth", "View|Canvas"), m_viewPanel, SLOT(canvasSmoothEvent()), g_keyConfig.getKey( "viewwin_view_ortho_smooth" ) ) ); m_canvasTexture = group->addAction( m_viewMenu->addAction( tr( "Canvas Texture", "View|Canvas"), m_viewPanel, SLOT(canvasTextureEvent()), g_keyConfig.getKey( "viewwin_view_ortho_textured" ) ) ); m_canvasAlpha = group->addAction( m_viewMenu->addAction( tr( "Canvas Alpha Blend", "View|Canvas"), m_viewPanel, SLOT(canvasAlphaEvent()), g_keyConfig.getKey( "viewwin_view_ortho_alpha" ) ) ); m_viewMenu->addSeparator(); // Num viewports group group = new QActionGroup(this); m_view1 = group->addAction( m_viewMenu->addAction( tr( "1 View", "View|Viewports"), m_viewPanel, SLOT(view1()), g_keyConfig.getKey( "viewwin_view_1" ) ) ); m_view1x2 = group->addAction( m_viewMenu->addAction( tr( "1x2 View", "View|Viewports"), m_viewPanel, SLOT(view1x2()), g_keyConfig.getKey( "viewwin_view_1x2" ) ) ); m_view2x1 = group->addAction( m_viewMenu->addAction( tr( "2x1 View", "View|Viewports"), m_viewPanel, SLOT(view2x1()), g_keyConfig.getKey( "viewwin_view_2x1" ) ) ); m_view2x2 = group->addAction( m_viewMenu->addAction( tr( "2x2 View", "View|Viewports"), m_viewPanel, SLOT(view2x2()), g_keyConfig.getKey( "viewwin_view_2x2" ) ) ); m_view2x3 = group->addAction( m_viewMenu->addAction( tr( "2x3 View", "View|Viewports"), m_viewPanel, SLOT(view2x3()), g_keyConfig.getKey( "viewwin_view_2x3" ) ) ); m_view3x2 = group->addAction( m_viewMenu->addAction( tr( "3x2 View", "View|Viewports"), m_viewPanel, SLOT(view3x2()), g_keyConfig.getKey( "viewwin_view_3x2" ) ) ); m_view3x3 = group->addAction( m_viewMenu->addAction( tr( "3x3 View", "View|Viewports"), m_viewPanel, SLOT(view3x3()), g_keyConfig.getKey( "viewwin_view_3x3" ) ) ); m_3dWire->setCheckable( true ); m_3dFlat->setCheckable( true ); m_3dSmooth->setCheckable( true ); m_3dTexture->setCheckable( true ); m_3dAlpha->setCheckable( true ); m_3dTexture->setChecked( true ); m_canvasWire->setCheckable( true ); m_canvasFlat->setCheckable( true ); m_canvasSmooth->setCheckable( true ); m_canvasTexture->setCheckable( true ); m_canvasAlpha->setCheckable( true ); m_canvasWire->setChecked( true ); m_view1->setCheckable( true ); m_view1x2->setCheckable( true ); m_view2x1->setCheckable( true ); m_view2x2->setCheckable( true ); m_view2x3->setCheckable( true ); m_view3x2->setCheckable( true ); m_view3x3->setCheckable( true ); int count = 4; bool tall = false; if ( g_prefs.exists( "ui_viewport_count" ) ) count = g_prefs( "ui_viewport_count" ).intValue(); if ( g_prefs.exists( "ui_viewport_tall" ) ) tall = (g_prefs( "ui_viewport_tall" ).intValue() != 0); switch ( count ) { case 1: m_view1->setChecked( true ); break; case 2: if ( tall ) m_view1x2->setChecked( true ); else m_view2x1->setChecked( true ); break; default: case 4: m_view2x2->setChecked( true ); break; case 6: if ( tall ) m_view2x3->setChecked( true ); else m_view3x2->setChecked( true ); break; case 9: m_view3x3->setChecked( true ); break; } m_viewMenu->addSeparator(); m_viewMenu->addAction( tr( "Viewport Settings...", "View|Viewport Settings" ), this, SLOT(viewportSettingsEvent()), g_keyConfig.getKey( "viewwin_view_viewport_settings" ) ); m_snapMenu = new QMenu( this ); connect( m_snapMenu, SIGNAL(triggered(QAction*)), this, SLOT(snapToSelectedEvent(QAction*)) ); m_snapToGrid = m_snapMenu->addAction( tr("Grid", "Tools|Snap to Grid") ); m_snapToGrid->setShortcut( g_keyConfig.getKey( "tool_snap_to_grid" ) ); m_snapToGrid->setCheckable( true ); m_snapToVertex = m_snapMenu->addAction( tr("Vertex", "Tools|Snap to Vertex") ); m_snapToVertex->setShortcut( g_keyConfig.getKey( "tool_snap_to_vertex" ) ); m_snapToVertex->setCheckable( true ); if ( g_prefs.exists( "ui_snap_grid" ) && g_prefs( "ui_snap_grid" ).intValue() != 0 ) { m_snapToGrid->setChecked( true ); } if ( g_prefs.exists( "ui_snap_vertex" ) && g_prefs( "ui_snap_vertex" ).intValue() != 0 ) { m_snapToVertex->setChecked( true ); } m_toolMenu = new QMenu( this ); m_snapMenu->setTitle( tr("Snap To") ); m_toolMenu->addMenu( m_snapMenu ); m_toolMenu->addSeparator(); m_toolBar = new QToolBar( this ); m_toolBar->setObjectName( "mainwin_toolbar" ); addToolBar( m_toolBar ); m_toolBar->setWindowTitle( tr( "Tools" ) ); //m_toolBar->setHorizontallyStretchable( true ); //m_toolBar->setVerticallyStretchable( true ); initializeToolbox(); m_modelMenu = new QMenu( this ); m_modelMenu->addAction( tr("Undo"), this, SLOT(undoRequest()), QKeySequence( tr("Ctrl+Z", "Undo shortcut" ) ) ); m_modelMenu->addAction( tr("Redo"), this, SLOT(redoRequest()), QKeySequence( tr("Ctrl+Y", "Redo shortcut" ) ) ); m_modelMenu->addSeparator(); m_modelMenu->addAction( tr("Edit Model Meta Data...", "Model|Edit Model Meta Data"), this, SLOT(metaWindowEvent()), g_keyConfig.getKey( "viewwin_model_edit_meta_data" ) ); m_modelMenu->addAction( tr("Transform Model...", "Model|Transform Model"), this, SLOT(transformWindowEvent()), g_keyConfig.getKey( "viewwin_model_transform" ) ); m_modelMenu->addAction( tr("Boolean Operation...", "Model|Boolean Operation"), this, SLOT(boolWindowEvent()), g_keyConfig.getKey( "viewwin_model_boolean_operation" ) ); m_modelMenu->addSeparator(); m_modelMenu->addAction( tr("Set Background Image...", "Model|Set Background Image"), this, SLOT(backgroundWindowEvent()), g_keyConfig.getKey( "viewwin_model_set_background_image" ) ); m_modelMenu->addAction( tr("Merge...", "Model|Merge"), this, SLOT(mergeModelsEvent()), g_keyConfig.getKey( "viewwin_model_merge" ) ); m_modelMenu->addAction( tr("Import Animations...", "Model|Import Animations"), this, SLOT(mergeAnimationsEvent()), g_keyConfig.getKey( "viewwin_model_import_animations" ) ); m_geometryMenu = new QMenu( this ); m_materialsMenu = new QMenu( this ); m_materialsMenu->addAction( tr("Edit Groups...", "Groups|Edit Groups"), this, SLOT(groupWindowEvent()), g_keyConfig.getKey( "viewwin_groups_edit_groups" ) ); m_materialsMenu->addAction( tr("Edit Materials...", "Groups|Edit Materials"), this, SLOT(textureWindowEvent()), g_keyConfig.getKey( "viewwin_groups_edit_materials" ) ); m_materialsMenu->addAction( tr("Clean Up Groups...", "Groups|Clean Up Groups"), this, SLOT(groupCleanWindowEvent()), g_keyConfig.getKey( "viewwin_groups_cleanup" ) ); m_materialsMenu->addAction( tr("Reload Textures", "Groups|Reload Textures"), this, SLOT(reloadTexturesEvent()), g_keyConfig.getKey( "viewwin_groups_reload_textures" ) ); m_materialsMenu->addSeparator(); m_materialsMenu->addAction( tr("Edit Projection...", "Groups|Edit Projection"), this, SLOT(projectionWindowEvent()), g_keyConfig.getKey( "viewwin_groups_edit_projection" ) ); m_materialsMenu->addAction( tr("Edit Texture Coordinates...", "Groups|Edit Texture Coordinates"), this, SLOT(textureCoordEvent()), g_keyConfig.getKey( "viewwin_groups_edit_texture_coordinates" ) ); m_materialsMenu->addAction( tr("Paint Texture...", "Groups|Paint Texture"), this, SLOT(paintTextureEvent()), g_keyConfig.getKey( "viewwin_groups_paint_texture" ) ); m_jointsMenu = new QMenu( this ); m_jointsMenu->addAction( tr( "Edit Joints...", "Joints|Edit Joints"), this, SLOT(jointWinEvent()), g_keyConfig.getKey( "viewwin_joints_edit_joints" ) ); m_jointsMenu->addAction( tr( "Assign Selected to Joint", "Joints|Assign Selected to Joint"), this, SLOT(jointAssignSelectedToJoint()), g_keyConfig.getKey( "viewwin_joints_assign_selected" ) ); m_jointsMenu->addAction( tr( "Auto-Assign Selected...", "Joints|Auto-Assign Selected"), this, SLOT(jointAutoAssignSelected()), g_keyConfig.getKey( "viewwin_joints_auto_assign_selected" ) ); m_jointsMenu->addAction( tr( "Remove All Influences from Selected", "Joints|Remove All Influences from Selected"), this, SLOT(jointRemoveInfluencesFromSelected()), g_keyConfig.getKey( "viewwin_joints_remove_influences" ) ); m_jointsMenu->addAction( tr( "Remove Selected Joint from Influencing", "Joints|Remove Selected Joint from Influencing"), this, SLOT(jointRemoveInfluenceJoint()), g_keyConfig.getKey( "viewwin_joints_remove_joint" ) ); m_jointsMenu->addSeparator(); m_jointsMenu->addAction( tr( "Convert Multiple Influences to Single", "Joints|Convert Multiple Influences to Single"), this, SLOT(jointMakeSingleInfluence()), g_keyConfig.getKey( "viewwin_joints_make_single_influence" ) ); m_jointsMenu->addSeparator(); m_jointsMenu->addAction( tr( "Select Joint Influences", "Joints|Select Joint Influences"), this, SLOT(jointSelectInfluenceJoints()), g_keyConfig.getKey( "viewwin_joints_select_joint_influences" ) ); m_jointsMenu->addAction( tr( "Select Influenced Vertices", "Joints|Select Influenced Vertices"), this, SLOT(jointSelectInfluencedVertices()), g_keyConfig.getKey( "viewwin_joints_select_influenced_vertices" ) ); m_jointsMenu->addAction( tr( "Select Influenced Points", "Joints|Select Influenced Points"), this, SLOT(jointSelectInfluencedPoints()), g_keyConfig.getKey( "viewwin_joints_select_influenced_points" ) ); m_jointsMenu->addAction( tr( "Select Unassigned Vertices", "Joints|Select Unassigned Vertices"), this, SLOT(jointSelectUnassignedVertices()), g_keyConfig.getKey( "viewwin_joints_select_unassigned_vertices" ) ); m_jointsMenu->addAction( tr( "Select Unassigned Points", "Joints|Select Unassigned Points"), this, SLOT(jointSelectUnassignedPoints()), g_keyConfig.getKey( "viewwin_joints_select_unassigned_points" ) ); initializeCommands(); //m_scriptMenu = new QPopupMenu( this ); m_animMenu = new QMenu( this ); m_startAnimItem = m_animMenu->addAction( tr("Start Animation Mode...", "Animation|Start Animation Mode"), this, SLOT(startAnimationMode()), g_keyConfig.getKey( "viewwin_anim_start_mode" ) ); m_stopAnimItem = m_animMenu->addAction( tr("Stop Animation Mode", "Animation|Stop Animation Mode"), this, SLOT(stopAnimationMode()), g_keyConfig.getKey( "viewwin_anim_stop_mode" ) ); m_animMenu->addSeparator(); m_animSetsItem = m_animMenu->addAction( tr("Animation Sets...", "Animation|Animation Sets"), this, SLOT(animSetWindowEvent()), g_keyConfig.getKey( "viewwin_anim_animation_sets" ) ); m_animExportItem = m_animMenu->addAction( tr("Save Animation Images...", "Animation|Save Animation Images"), this, SLOT(animExportWindowEvent()), g_keyConfig.getKey( "viewwin_anim_save_images" ) ); m_animMenu->addSeparator(); m_animCopyFrame = m_animMenu->addAction( tr("Copy Animation Frame", "Animation|Copy Animation Frame"), this, SLOT(animCopyFrameEvent()), g_keyConfig.getKey( "viewwin_anim_frame_copy" ) ); m_animPasteFrame = m_animMenu->addAction( tr("Paste Animation Frame", "Animation|Paste Animation Frame"), this, SLOT(animPasteFrameEvent()), g_keyConfig.getKey( "viewwin_anim_frame_paste" ) ); m_animClearFrame = m_animMenu->addAction( tr("Clear Animation Frame", "Animation|Clear Animation Frame"), this, SLOT(animClearFrameEvent()), g_keyConfig.getKey( "viewwin_anim_frame_clear" ) ); m_animMenu->addSeparator(); m_animCopySelected = m_animMenu->addAction( tr("Copy Selected Keyframes", "Animation|Copy Animation Frame"), this, SLOT(animCopySelectedEvent()), g_keyConfig.getKey( "viewwin_anim_selected_copy" ) ); m_animPasteSelected = m_animMenu->addAction( tr("Paste Selected Keyframes", "Animation|Paste Animation Frame"), this, SLOT(animPasteSelectedEvent()), g_keyConfig.getKey( "viewwin_anim_selected_paste" ) ); m_animMenu->addSeparator(); m_animSetRotItem = m_animMenu->addAction( tr("Set Rotation Keyframe", "Animation|Set Rotation Keyframe"), this, SLOT(animSetRotEvent()), g_keyConfig.getKey( "viewwin_anim_set_rotation" ) ); m_animSetTransItem = m_animMenu->addAction( tr("Set Translation Keyframe", "Animation|Set Translation Keyframe"), this, SLOT(animSetTransEvent()), g_keyConfig.getKey( "viewwin_anim_set_translation" ) ); m_stopAnimItem->setEnabled( false ); m_animSetRotItem->setEnabled( false ); m_animSetTransItem->setEnabled( false ); m_animCopyFrame->setEnabled( false ); m_animPasteFrame->setEnabled( false ); m_animClearFrame->setEnabled( false ); m_animCopySelected->setEnabled( false ); m_animPasteSelected->setEnabled( false ); m_helpMenu = new QMenu( this ); m_helpMenu->addAction( tr("Contents...", "Help|Contents"), this, SLOT(helpWindowEvent()), g_keyConfig.getKey( "viewwin_help_contents" ) ); m_helpMenu->addAction( tr("License...", "Help|License"), this, SLOT(licenseWindowEvent()), g_keyConfig.getKey( "viewwin_help_license" ) ); m_helpMenu->addAction( tr("About...", "Help|About"), this, SLOT(aboutWindowEvent()), g_keyConfig.getKey( "viewwin_help_about" ) ); m_menuBar = menuBar(); m_fileMenu->setTitle( tr("&File", "menu bar") ); m_menuBar->addMenu( m_fileMenu ); m_viewMenu->setTitle( tr("&View", "menu bar") ); m_menuBar->addMenu( m_viewMenu ); m_toolMenu->setTitle( tr("&Tools", "menu bar") ); m_menuBar->addMenu( m_toolMenu ); m_modelMenu->setTitle( tr("&Model", "menu bar") ); m_menuBar->addMenu( m_modelMenu ); m_geometryMenu->setTitle( tr("&Geometry", "menu bar") ); m_menuBar->addMenu( m_geometryMenu ); m_materialsMenu->setTitle( tr("Mate&rials", "menu bar") ); m_menuBar->addMenu( m_materialsMenu ); m_jointsMenu->setTitle( tr("&Influences", "menu bar") ); m_menuBar->addMenu( m_jointsMenu ); m_animMenu->setTitle( tr("&Animation", "menu bar") ); m_menuBar->addMenu( m_animMenu ); m_helpMenu->setTitle( tr("&Help", "menu bar") ); m_menuBar->addMenu( m_helpMenu ); resize( g_prefs.exists( "ui_viewwin_width") ? g_prefs( "ui_viewwin_width" ) : 900, g_prefs.exists( "ui_viewwin_height") ? g_prefs( "ui_viewwin_height" ) : 700 ); setMinimumSize( 520, 520 ); frameAllEvent(); m_viewPanel->modelUpdatedEvent(); show(); QTimer * m_savedTimer = new QTimer(); connect( m_savedTimer, SIGNAL(timeout()), this, SLOT(savedTimeoutCheck()) ); m_savedTimer->start( 1000 ); QString windowPos; loadDockPositions(); stopAnimationMode(); m_model->setUndoEnabled( true ); m_model->clearUndo(); // This is a hack to prevent a minimized bool panel from blocking the left // side of the menu bar. if ( !m_boolPanel->isVisible() ) { m_boolPanel->show(); m_boolPanel->hide(); } } ViewWindow::~ViewWindow() { log_debug( "deleting view window\n" ); _winList.remove( this ); log_debug( "deleting view window %08X, model %08X\n", this, m_model ); DecalManager::getInstance()->unregisterModel( m_model ); m_viewPanel->freeTextures(); delete m_model; m_viewPanel->setModel( NULL ); model_show_alloc_stats(); // QToolBar actually deletes buttons, we just need to delete array delete[] m_toolButtons; if ( !_shuttingDown ) { if ( _winList.empty() && qApp->quitOnLastWindowClosed() ) { ui_exit(); } } delete m_toolbox; } void ViewWindow::setModel( Model * model ) { m_viewPanel->setModel( model ); m_statusBar->setModel( model ); m_transformWin->setModel( model ); m_model = model; if ( m_model ) { Model::DrawJointModeE jointMode = static_cast( g_prefs( "ui_draw_joints" ).intValue() ); if ( jointMode != Model::JOINTMODE_LINES ) { jointMode = Model::JOINTMODE_BONES; } m_model->setDrawJoints( jointMode ); g_prefs( "ui_draw_joints" ) = (int) jointMode; } updateCaption(); //m_contextPanel->setModel( m_model ); if ( m_animWin->isVisible() ) { m_animWidget->initialize( m_model, true ); // Treat it like an undo } m_viewPanel->modelUpdatedEvent(); emit modelChanged( m_model ); while ( m_model->hasErrors() ) { std::string str = m_model->popError(); model_status( m_model, StatusError, STATUSTIME_LONG, "%s", str.c_str() ); } if ( m_currentTool ) { m_currentTool->setModel( m_model ); } for ( CommandMenuItemList::iterator it = m_primitiveCommands.begin(); it != m_primitiveCommands.end(); ++it ) { (*it)->widget->setModel( m_model ); } } bool ViewWindow::emptyWindow() { if ( m_model ) { // if no model is loaded and default scene is unmodified return ( strcmp( m_model->getFilename(), "" ) == 0 && m_model->getSaved() == true && !m_model->canRedo() ); } return true; } bool ViewWindow::getSaved() { if ( m_model ) { return m_model->getSaved(); } return true; } void ViewWindow::resizeEvent ( QResizeEvent * e ) { int w = e->size().width(); int h = e->size().height(); /* m_menuBar->move( 0, 0 ); m_menuBar->resize( w, m_menuBar->height() ); m_viewPanel->move( 0, m_menuBar->height() ); m_viewPanel->resize( w, h - m_menuBar->height() - m_statusBar->height() ); m_statusBar->move( 0, h - m_statusBar->height() ); m_statusBar->resize( w, m_statusBar->height() ); */ g_prefs( "ui_viewwin_width" ) = w; g_prefs( "ui_viewwin_height" ) = h; QMainWindow::resizeEvent(e); } /* void ViewWindow::resizeEvent ( QResizeEvent * e ) { int w = e->size().width(); int h = e->size().height(); m_menuBar->move( 0, 0 ); m_menuBar->resize( w, m_menuBar->height() ); m_viewPanel->move( 0, m_menuBar->height() ); m_viewPanel->resize( w, h - m_menuBar->height() - m_statusBar->height() ); m_statusBar->move( 0, h - m_statusBar->height() ); m_statusBar->resize( w, m_statusBar->height() ); g_prefs( "ui_viewwin_width" ) = w; g_prefs( "ui_viewwin_height" ) = h; } */ void ViewWindow::helpNowEvent() { HelpWin * win = new HelpWin( "olh_mainwin.html", false ); win->show(); } void ViewWindow::contextMenuEvent( QContextMenuEvent * e ) { e->ignore(); } void ViewWindow::saveModelEvent() { const char * filename = m_model->getFilename(); if ( filename && filename[0] ) { Model::ModelErrorE err = FilterManager::getInstance()->writeFile( m_model, filename, false ); if ( err == Model::ERROR_NONE ) { m_model->setSaved( true ); prefs_recent_model( filename ); } else { m_abortQuit = true; if ( Model::operationFailed( err ) ) { QString reason = modelErrStr( err, m_model ); reason = QString(filename) + QString(":\n") + reason; msg_error( (const char *) reason.toUtf8() ); } } } else { saveModelAsEvent(); } } void ViewWindow::saveModelAsEvent() { saveModelInternal( m_model, false ); } void ViewWindow::exportModelEvent() { saveModelInternal( m_model, true ); } void ViewWindow::exportSelectedEvent() { if ( m_model->getSelectedTriangleCount() == 0 && m_model->getSelectedPointCount() == 0 && m_model->getSelectedProjectionCount() == 0 ) { model_status( m_model, StatusError, STATUSTIME_LONG, tr( "You must have at least 1 face, joint, or point selected to Export Selected" ).toUtf8() ); return; } Model * m = m_model->copySelected(); if ( !m ) return; saveModelInternal( m, true ); delete m; } void ViewWindow::saveModelInternal( Model * model, bool exportModel ) { list formats = FilterManager::getInstance()->getAllWriteTypes( exportModel ); QString formatsStr = ((exportModel) ? tr( "All Exportable Formats" ) : tr( "All Writable Formats" )) + QString(" (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += QString( " " ); } } formatsStr += QString( ")" ); const char * modelFile = model->getFilename(); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( exportModel ) { dir = QString::fromUtf8( g_prefs( "ui_export_dir" ).stringValue().c_str() ); } else { if ( modelFile && modelFile[0] != '\0' ) { std::string fullname; std::string fullpath; std::string basename; normalizePath( modelFile, fullname, fullpath, basename ); dir = tr( fullpath.c_str() ); } } if ( dir.isEmpty() ) { dir = QString( "." ); } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setAcceptMode( QFileDialog::AcceptSave ); if ( exportModel ) { d.selectFile( QString( model->getExportFile() ) ); } d.setWindowTitle( tr( "Save model file as" ) ); if ( exportModel ) { d.setWindowTitle( tr( "Export model" ) ); } d.selectNameFilter( formatsStr ); d.setFileMode( QFileDialog::AnyFile ); m_abortQuit = true; bool again = true; while ( again ) { again = false; if ( QDialog::Accepted == d.exec() ) { bool save = true; QStringList files = d.selectedFiles(); if ( save && !files.empty() ) { std::string filename = (const char *) files[0].toUtf8(); if ( !strchr(filename.c_str(), '.' ) ) { filename += ".mm3d"; } Model::ModelErrorE err = FilterManager::getInstance()->writeFile( model, filename.c_str(), exportModel ); if ( err == Model::ERROR_NONE ) { m_abortQuit = false; if ( exportModel ) { g_prefs( "ui_export_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); model->setExportFile( filename.c_str() ); } else { model->setSaved( true ); model->setFilename( filename.c_str() ); g_prefs( "ui_model_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); } prefs_recent_model( (const char *) filename.c_str() ); updateCaption(); } else { if ( Model::operationFailed( err ) ) { msg_error( modelErrStr( err, model ).toUtf8() ); } } } } } } void ViewWindow::mergeModelsEvent() { list formats = FilterManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats", "model formats" ) + QString( " (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += QString( " " ); } } formatsStr += QString(")"); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = "."; } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setWindowTitle( tr( "Open model file" ) ); d.selectNameFilter( formatsStr ); if ( QDialog::Accepted == d.exec() ) { QStringList files = d.selectedFiles(); if ( files.empty() ) return; std::string filename = (const char *) files[0].toUtf8(); Model::ModelErrorE err; Model * model = new Model(); if ( (err = FilterManager::getInstance()->readFile( model, filename.c_str() )) == Model::ERROR_NONE) { model_show_alloc_stats(); MergeWindow mw( model, this ); if ( mw.exec() ) { Model::AnimationMergeE mode = Model::AM_NONE; if ( mw.getIncludeAnimation() ) { mode = Model::AM_ADD; if ( mw.getAnimationMerge() ) { mode = Model::AM_MERGE; } } double rot[3]; double trans[3]; mw.getRotation( rot ); mw.getTranslation( trans ); m_model->mergeModels( model, mw.getIncludeTexture(), mode, true, trans, rot ); m_model->operationComplete( tr("Merge models").toUtf8() ); g_prefs( "ui_model_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); m_viewPanel->modelUpdatedEvent(); } prefs_recent_model( filename.c_str() ); delete model; } else { if ( Model::operationFailed( err ) ) { QString reason = modelErrStr( err, model ); reason = tr(filename.c_str()) + tr(":\n") + reason; msg_error( (const char *) reason.toUtf8() ); } delete model; } } } void ViewWindow::mergeAnimationsEvent() { list formats = FilterManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats", "model formats") + QString( " (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += QString( " " ); } } formatsStr += QString( ")" ); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = "."; } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setWindowTitle( tr( "Open model file" ) ); d.selectNameFilter( formatsStr ); if ( QDialog::Accepted == d.exec() ) { QStringList files = d.selectedFiles(); if ( files.empty() ) return; std::string filename = (const char *) files[0].toUtf8(); Model::ModelErrorE err; Model * model = new Model(); if ( (err = FilterManager::getInstance()->readFile( model, filename.c_str() )) == Model::ERROR_NONE) { model_show_alloc_stats(); m_model->mergeAnimations( model ); prefs_recent_model( filename.c_str() ); delete model; } else { if ( Model::operationFailed( err ) ) { QString reason = modelErrStr( err, model ); reason = tr(filename.c_str()) + tr(":\n") + reason; msg_error( (const char *) reason.toUtf8() ); } delete model; } } } void ViewWindow::scriptEvent() { #ifdef HAVE_LUALIB QString dir = QString::fromUtf8( g_prefs( "ui_script_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = QString("."); } QString formatsStr = QString( "Lua scripts (*.lua)" ); QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setWindowTitle( tr( "Open model file" ) ); d.selectNameFilter( formatsStr ); if ( QDialog::Accepted == d.exec() ) { QStringList files = d.selectedFiles(); if ( files.empty() ) return; g_prefs( "ui_script_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); std::string filename = (const char *) files[0].toUtf8(); runScript( filename.c_str() ); } #endif // HAVE_LUALIB } void ViewWindow::runScript( const char * filename ) { #ifdef HAVE_LUALIB if ( filename ) { LuaScript lua; LuaContext lc( m_model ); luaif_registerfunctions( &lua, &lc ); std::string scriptfile = filename; std::string fullname; std::string fullpath; std::string basename; normalizePath( scriptfile.c_str(), fullname, fullpath, basename ); log_debug( "running script %s\n", basename.c_str() ); int rval = lua.runFile( scriptfile.c_str() ); prefs_recent_script( filename ); if ( rval == 0 ) { log_debug( "script complete, exited normally\n" ); QString str = tr("Script %1 complete").arg(basename.c_str()); model_status( m_model, StatusNormal, STATUSTIME_SHORT, "%s", (const char *) str.toUtf8() ); } else { log_error( "script complete, exited with error code %d\n", rval ); QString str = tr("Script %1 error %2") .arg(basename.c_str()) .arg(lua.error()); model_status( m_model, StatusError, STATUSTIME_LONG, "%s", (const char *) str.toUtf8() ); } m_model->setNoAnimation(); m_model->operationComplete( basename.c_str() ); m_viewPanel->modelUpdatedEvent(); } #endif // HAVE_LUALIB } void ViewWindow::closeEvent( QCloseEvent * e ) { saveDockPositions(); #ifdef CODE_DEBUG e->accept(); #else // CODE_DEBUG if ( ! m_model->getSaved() ) { int val = QMessageBox::warning( this, tr("Save first?"), tr("Model has been modified\nDo you want to save before closing?"), QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel ); switch ( val ) { case QMessageBox::Yes: m_abortQuit = false; saveModelEvent(); if ( ! m_abortQuit ) { e->accept(); } break; case QMessageBox::No: e->accept(); break; case QMessageBox::Cancel: e->ignore(); break; default: { QString str = tr( "Unknown response: %1, Canceling close request" ) .arg( val ); msg_error( (const char *) str.toUtf8() ); } e->ignore(); break; } } else { e->accept(); } #endif // CODE_DEBUG } QAction * ViewWindow::insertMenuItem( QMenu * parentMenu, bool isTool, const QString & path, const QString & name, QMenu * subMenu ) { QMenu * addMenu = parentMenu; if ( path.length() != 0 ) { bool found = false; MenuItemList::iterator it; for ( it = m_menuItems.begin(); it != m_menuItems.end(); it++ ) { if ( it->text == path ) { addMenu = it->menu; found = true; } } if ( !found ) { // TODO deal with multi-level paths addMenu = new QMenu( this ); QString module; if ( isTool ) { module = "Tool"; connect( addMenu, SIGNAL(triggered(QAction*)), this, SLOT(toolActivated(QAction*))); } else { module = "Command"; } addMenu->setTitle( qApp->translate( module.toUtf8(), path.toUtf8() ) ); parentMenu->addMenu( addMenu ); MenuItemT mi; mi.text = path; mi.menu = addMenu; m_menuItems.push_back( mi ); } } QAction * id; if ( subMenu ) { subMenu->setTitle( name ); id = addMenu->addMenu( subMenu ); } else { id = addMenu->addAction( name ); } log_debug( "added %s as id %d\n", (const char *) name.toUtf8(), id ); return id; } void ViewWindow::frameAllEvent() { double x1, y1, z1, x2, y2, z2; if ( m_model->getBoundingRegion( &x1, &y1, &z1, &x2, &y2, &z2 ) ) { m_viewPanel->frameArea( x1, y1, z1, x2, y2, z2 ); } } void ViewWindow::frameSelectedEvent() { double x1, y1, z1, x2, y2, z2; if ( m_model->getSelectedBoundingRegion( &x1, &y1, &z1, &x2, &y2, &z2 ) ) { m_viewPanel->frameArea( x1, y1, z1, x2, y2, z2 ); } } void ViewWindow::showContextEvent() { m_viewPanel->modelUpdatedEvent(); // Set model so that it is properly initialized before display m_contextPanel->setModel( m_model ); m_contextPanel->show(); m_contextPanel->raise(); // Set model again so that it actually displays properties m_contextPanel->setModel( m_model ); } void ViewWindow::renderBadEvent() { g_prefs( "ui_render_bad_textures" ) = 1; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::noRenderBadEvent() { g_prefs( "ui_render_bad_textures" ) = 0; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::renderBackface() { g_prefs( "ui_render_backface_cull" ) = 0; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::noRenderBackface() { g_prefs( "ui_render_backface_cull" ) = 1; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::renderProjections() { g_prefs( "ui_render_projections" ) = 0; m_model->setDrawProjections( true ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::noRenderProjections() { bool doHide = true; if ( m_model->getSelectedProjectionCount() > 0 ) { doHide = false; char ch = msg_info_prompt( (const char *) tr("Cannot hide with selected projections. Unselect projections now?").toUtf8(), "yN" ); if ( toupper(ch) == 'Y' ) { doHide = true; m_model->unselectAll(); m_model->operationComplete( tr("Hide projections").toUtf8() ); } } if ( doHide ) { g_prefs( "ui_render_projections" ) = 1; m_model->setDrawProjections( false ); m_viewPanel->modelUpdatedEvent(); } } void ViewWindow::renderSelectionEvent() { g_prefs( "ui_render_3d_selections" ) = 1; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::noRenderSelectionEvent() { g_prefs( "ui_render_3d_selections" ) = 0; m_viewPanel->modelUpdatedEvent(); } void ViewWindow::boneJointHide() { bool doHide = true; if ( m_model->getSelectedBoneJointCount() > 0 ) { doHide = false; char ch = msg_info_prompt( (const char *) tr("Cannot hide with selected joints. Unselect joints now?").toUtf8(), "yN" ); if ( toupper(ch) == 'Y' ) { doHide = true; m_model->unselectAll(); m_model->operationComplete( tr("Hide bone joints").toUtf8() ); } } if ( doHide ) { m_model->setDrawJoints( Model::JOINTMODE_NONE ); m_viewPanel->modelUpdatedEvent(); } } void ViewWindow::boneJointLines() { Model::DrawJointModeE m = Model::JOINTMODE_LINES; g_prefs( "ui_draw_joints" ) = (int) m; m_model->setDrawJoints( m ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::boneJointBones() { Model::DrawJointModeE m = Model::JOINTMODE_BONES; g_prefs( "ui_draw_joints" ) = (int) m; m_model->setDrawJoints( m ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::viewportSettingsEvent() { ViewportSettings * win = new ViewportSettings(); win->show(); } void ViewWindow::toolActivated( QAction * id ) { log_debug( "toolActivated(%p)\n", id ); for ( ToolMenuItemList::iterator it = m_tools.begin(); it != m_tools.end(); ++it ) { if ( (*it)->id == id ) { ::Tool * tool = (*it)->tool; for ( int t = 0; t < m_toolCount; t++ ) { if ( m_toolList[t] == tool ) { if ( !m_toolButtons[t]->isChecked() ) { m_toolButtons[t]->setChecked( true ); } m_currentTool = m_toolList[ t ]; } } return; } } } void ViewWindow::scriptActivated( QAction * id ) { } void ViewWindow::groupWindowEvent() { GroupWindow * win = new GroupWindow( m_model ); win->show(); } void ViewWindow::textureWindowEvent() { TextureWindow * win = new TextureWindow( m_model ); win->show(); } void ViewWindow::groupCleanWindowEvent() { GroupCleanWin * win = new GroupCleanWin( m_model ); win->show(); } void ViewWindow::textureCoordEvent() { if ( m_model->getSelectedTriangleCount() > 0 ) { m_textureCoordWin->show(); m_textureCoordWin->raise(); } else { msg_info( (const char *) tr("You must select faces first.\nUse the 'Select Faces' tool.", "Notice that user must have faces selected to open 'edit texture coordinates' window" ).toUtf8()); } } void ViewWindow::paintTextureEvent() { if ( m_model->getSelectedTriangleCount() > 0 ) { PaintTextureWin * win = new PaintTextureWin( m_model ); win->show(); } else { msg_info( (const char *) tr("You must select faces first.\nUse the 'Select Faces' tool.", "Notice that user must have faces selected to open 'paint texture' window").toUtf8() ); } } // ContextPanelObserver method void ViewWindow::showProjectionEvent() { projectionWindowEvent(); } void ViewWindow::projectionWindowEvent() { m_projectionWin->show(); m_projectionWin->raise(); } void ViewWindow::transformWindowEvent() { m_transformWin->show(); m_transformWin->raise(); } void ViewWindow::metaWindowEvent() { MetaWindow * win = new MetaWindow( m_model ); win->show(); } void ViewWindow::boolWindowEvent() { m_boolPanel->show(); m_boolPanel->raise(); } void ViewWindow::reloadTexturesEvent() { if( TextureManager::getInstance()->reloadTextures() ) { invalidateModelTextures(); } } void ViewWindow::editDisableEvent() { m_canEdit = false; m_viewPanel->setEnabled( m_canEdit ); } void ViewWindow::editEnableEvent() { m_canEdit = true; m_viewPanel->setEnabled( m_canEdit ); } void ViewWindow::undoRequest() { log_debug( "undo request\n" ); if ( m_model->canUndo() ) { const char * opname = m_model->getUndoOpName(); if ( m_animWin->isVisible() ) { m_animWidget->undoRequest(); } else { m_model->undo(); if ( m_model->getAnimationMode() ) { m_animWidget->initialize( m_model, true ); animationModeOn(); m_animWin->show(); } else { m_viewPanel->modelUpdatedEvent(); } } QString str = tr( "Undo %1" ).arg( (opname && opname[0]) ? opname : "" ); model_status ( m_model, StatusNormal, STATUSTIME_SHORT, "%s", (const char *) str.toUtf8() ); if ( m_model->getSelectedBoneJointCount() > 0 ) { m_model->setDrawJoints( (Model::DrawJointModeE) g_prefs( "ui_draw_joints" ).intValue() ); m_viewPanel->modelUpdatedEvent(); } } else { model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Nothing to undo").toUtf8() ); } } void ViewWindow::redoRequest() { log_debug( "redo request\n" ); if ( m_model->canRedo() ) { const char * opname = m_model->getRedoOpName(); if ( m_animWin->isVisible() ) { m_animWidget->redoRequest(); } else { m_model->redo(); if ( m_model->getAnimationMode() ) { m_animWidget->initialize( m_model, true ); animationModeOn(); m_animWin->show(); } else { m_viewPanel->modelUpdatedEvent(); } } if ( m_model->getSelectedBoneJointCount() > 0 ) { m_model->setDrawJoints( (Model::DrawJointModeE) g_prefs( "ui_draw_joints" ).intValue() ); m_viewPanel->modelUpdatedEvent(); } QString str = tr( "Redo %1" ).arg( (opname && opname[0]) ? opname : "" ); model_status ( m_model, StatusNormal, STATUSTIME_SHORT, "%s", (const char *) str.toUtf8() ); } else { model_status( m_model, StatusNormal, STATUSTIME_SHORT, tr("Nothing to redo").toUtf8() ); } } void ViewWindow::snapToSelectedEvent( QAction * snapTo ) { log_debug( "snapToSelectedEvent( %d )\n", snapTo ); g_prefs( "ui_snap_grid" ) = ( m_snapToGrid->isChecked() ) ? 1 : 0; g_prefs( "ui_snap_vertex" ) = ( m_snapToVertex->isChecked() ) ? 1 : 0; } void ViewWindow::helpWindowEvent() { HelpWin * win = new HelpWin(); win->show(); } void ViewWindow::aboutWindowEvent() { AboutWin * win = new AboutWin(); win->show(); } void ViewWindow::licenseWindowEvent() { LicenseWin * win = new LicenseWin(); win->show(); } void ViewWindow::animSetWindowEvent() { if ( m_animWin->isVisible() ) { stopAnimationMode(); } AnimSetWindow asw( m_model, this ); asw.exec(); } void ViewWindow::animExportWindowEvent() { if ( m_model->getAnimCount( Model::ANIMMODE_SKELETAL ) > 0 || m_model->getAnimCount( Model::ANIMMODE_FRAME ) > 0 ) { AnimExportWindow aew( m_model, m_viewPanel, this ); aew.exec(); } else { msg_error( (const char *) tr("This model does not have any animations").toUtf8() ); } } void ViewWindow::animSetRotEvent() { double point[3] = { 0.0, 0.0, 0.0 }; Matrix m; m.loadIdentity(); m_model->rotateSelected( m, point ); m_model->operationComplete( tr("Set rotation keframe").toUtf8() ); } void ViewWindow::animSetTransEvent() { Matrix m; m.loadIdentity(); m_model->translateSelected( m ); m_model->operationComplete( tr("Set translation keframe").toUtf8() ); } void ViewWindow::animCopyFrameEvent() { if ( m_animWin->isVisible() ) { m_animPasteFrame->setEnabled( false ); m_animPasteSelected->setEnabled( false ); if ( m_animWidget->copyFrame( false ) ) { m_animPasteFrame->setEnabled( true ); } } } void ViewWindow::animPasteFrameEvent() { if ( m_animWin->isVisible() ) { m_animWidget->pasteFrame(); } } void ViewWindow::animCopySelectedEvent() { if ( m_animWin->isVisible() ) { m_animPasteFrame->setEnabled( false ); m_animPasteSelected->setEnabled( false ); if ( m_animWidget->copyFrame( true ) ) { m_animPasteSelected->setEnabled( true ); } } } void ViewWindow::animPasteSelectedEvent() { animPasteFrameEvent(); // Same logic for both } void ViewWindow::animClearFrameEvent() { if ( m_animWin->isVisible() ) { m_animWidget->clearFrame(); } } void ViewWindow::startAnimationMode() { m_animWidget->initialize( m_model, false ); animationModeOn(); m_animWin->show(); } void ViewWindow::stopAnimationMode() { m_animWin->close(); m_animWidget->stopAnimationMode(); animationModeOff(); } void ViewWindow::animationModeOn() { m_animExportItem->setEnabled( false ); m_startAnimItem->setEnabled( false ); m_stopAnimItem->setEnabled( true ); m_animSetRotItem->setEnabled( true ); m_animSetTransItem->setEnabled( true ); m_animCopyFrame->setEnabled( true ); m_animPasteFrame->setEnabled( false ); // Disabled until copy occurs m_animClearFrame->setEnabled( true ); m_animCopySelected->setEnabled( true ); m_animPasteSelected->setEnabled( false ); // Disabled until copy occurs } void ViewWindow::animationModeOff() { m_model->setNoAnimation(); m_viewPanel->modelUpdatedEvent(); m_animWin->close(); m_animExportItem->setEnabled( true ); m_startAnimItem->setEnabled( true ); m_stopAnimItem->setEnabled( false ); m_animSetRotItem->setEnabled( false ); m_animSetTransItem->setEnabled( false ); m_animCopyFrame->setEnabled( false ); m_animPasteFrame->setEnabled( false ); m_animClearFrame->setEnabled( false ); m_animCopySelected->setEnabled( false ); m_animPasteSelected->setEnabled( false ); editEnableEvent(); } void ViewWindow::contextPanelHidden() { m_showContext->setText( tr( "Show Properties", "View|Show Properties") ); //m_viewPanel->modelUpdatedEvent(); } void ViewWindow::buttonToggled( bool on ) { if ( on ) { if ( m_currentTool ) m_currentTool->deactivated(); for ( int t = 0; t < m_toolCount; t++ ) { if ( m_toolButtons[t]->isChecked() ) { if ( m_last != m_toolButtons[t] ) { m_currentTool = m_toolList[ t ]; m_currentTool->activated( 0, m_model, this ); m_toolbox->setCurrentTool( m_currentTool ); break; } } } } } static void _registerKeyBinding( ::Tool * tool, int index, QMenu * menu, QAction * id ) { QString name = QString( "tool_" ) + QString::fromUtf8( tool->getName( 0 ) ); if ( index > 0 ) { name += QString( "_" ) + QString::fromUtf8( tool->getName( index ) ); } name = name.replace( QString("."), QString("") ); name = name.replace( QString(" "), QString("_") ); name = name.toLower(); QKeySequence key = g_keyConfig.getKey( (const char *) name.toUtf8() ); if ( !key.isEmpty() ) { id->setShortcut( key ); } } static QString _makeToolTip( ::Tool * tool, int index ) { QString lookupStr = QString( "tool_" ) + QString::fromUtf8( tool->getName( 0 ) ); if ( index > 0 ) { lookupStr += QString( "_" ) + QString::fromUtf8( tool->getName( index ) ); } lookupStr = lookupStr.replace( QString("."), QString("") ); lookupStr = lookupStr.replace( QString(" "), QString("_") ); lookupStr = lookupStr.toLower(); QKeySequence key = g_keyConfig.getKey( (const char *) lookupStr.toUtf8() ); QString name = qApp->translate( "Tool", tool->getName( index ) ); if ( !key.isEmpty() ) { name += QString(" ("); name += key.toString(); name += QString(")"); } return name; } void ViewWindow::initializeToolbox() { connect( m_toolMenu, SIGNAL(triggered(QAction*)), this, SLOT(toolActivated(QAction*))); m_toolbox->registerAllTools(); QActionGroup * grp = new QActionGroup( this ); m_toolButtons = new QActionPtr[ m_toolbox->getToolCount() ]; m_toolList = new ToolPtr[ m_toolbox->getToolCount() ]; m_toolCount = 0; ::Tool * tool = m_toolbox->getFirstTool(); while ( tool ) { if ( !tool->isSeparator() ) { ToolMenuItemT * item; QAction * id; int count = tool->getToolCount(); if ( count > 1 ) { QMenu * menu = new QMenu( this ); connect( menu, SIGNAL(triggered(QAction*)), this, SLOT(toolActivated(QAction*))); for ( int t = 1; t < count; t++ ) { const char * name = tool->getName( t ); id = menu->addAction( qApp->translate( "Tool", name ) ); _registerKeyBinding( tool, t, menu, id ); item = new ToolMenuItemT; item->id = id; item->tool = tool; item->arg = t; m_tools.push_back( item ); // Create tool button QIcon set; set.addPixmap( QPixmap( tool->getPixmap() ) ); m_toolList[m_toolCount] = tool; // Text below m_toolButtons[ m_toolCount ] = m_toolBar->addAction( set, qApp->translate( "Tool", tool->getName(t) ) ); m_toolButtons[ m_toolCount ]->setCheckable( true ); if ( name && name[0] ) { m_toolButtons[ m_toolCount ]->setToolTip( _makeToolTip( tool, t ) ); } connect( m_toolButtons[m_toolCount], SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool))); grp->addAction( m_toolButtons[ m_toolCount ] ); m_toolCount++; } //id = m_toolMenu->addAction( qApp->translate( "Tool", tool->getName(0)), menu ); id = insertMenuItem( m_toolMenu, true, tool->getPath(), qApp->translate( "Tool", tool->getName(0)), menu ); _registerKeyBinding( tool, 0, m_toolMenu, id ); item = new ToolMenuItemT; item->id = id; item->tool = tool; item->arg = 0; m_tools.push_back( item ); } else { const char * name = tool->getName( 0 ); //id = m_toolMenu->addAction( qApp->translate( "Tool", name ) ); id = insertMenuItem( m_toolMenu, true, tool->getPath(), qApp->translate( "Tool", tool->getName(0)), NULL ); _registerKeyBinding( tool, 0, m_toolMenu, id ); item = new ToolMenuItemT; item->id = id; item->tool = tool; item->arg = 0; m_tools.push_back( item ); // Create tool button QIcon set; set.addPixmap( QPixmap( tool->getPixmap() ) ); m_toolList[m_toolCount] = tool; // Text below m_toolButtons[ m_toolCount ] = m_toolBar->addAction( set, qApp->translate( "Tool", tool->getName(0) ) ); m_toolButtons[ m_toolCount ]->setCheckable( true ); if ( name && name[0] ) { m_toolButtons[ m_toolCount ]->setToolTip( _makeToolTip( tool, 0 ) ); } connect( m_toolButtons[m_toolCount], SIGNAL(toggled(bool)), this, SLOT(buttonToggled(bool))); grp->addAction( m_toolButtons[ m_toolCount ] ); m_toolCount++; } } else { m_toolMenu->addSeparator(); } tool = m_toolbox->getNextTool(); } } static void _registerKeyBinding( Command * cmd, int index, QMenu * menu, QAction * id ) { QString name = QString( "cmd_" ) + QString( cmd->getName( 0 ) ); if ( index > 0 ) { name += QString( "_" ) + QString( cmd->getName( index ) ); } name = name.replace( QString("."), QString("") ); name = name.replace( QString(" "), QString("_") ); name = name.toLower(); QKeySequence key = g_keyConfig.getKey( (const char *) name.toUtf8() ); if ( !key.isEmpty() ) { id->setShortcut( key ); } } void ViewWindow::initializeCommands() { //m_cmdMgr = new CommandManager(); //init_std_cmds( m_cmdMgr ); m_cmdMgr = CommandManager::getInstance(); Command * cmd = m_cmdMgr->getFirstCommand(); while ( cmd ) { if ( !cmd->isSeparator() ) { CommandMenuItemT * item; QAction * id; int count = cmd->getCommandCount(); if ( count > 1 ) { QMenu * menu = new QMenu( this ); for ( int t = 1; t < count; t++ ) { id = menu->addAction( qApp->translate( "Command", cmd->getName(t) ) ); item = new CommandMenuItemT; item->id = id; item->command = cmd; item->arg = t; item->widget = new CommandWidget(this, m_model, &m_canEdit, cmd, t ); connect(id, SIGNAL(triggered(bool)), item->widget, SLOT(activateCommand(bool))); _registerKeyBinding( cmd, t, menu, id ); m_primitiveCommands.push_back( item ); } log_debug( "adding command '%s' to menus\n", cmd->getName(0) ); id = insertMenuItem( m_geometryMenu, false, cmd->getPath(), qApp->translate( "Command", cmd->getName(0) ), menu ); //id = m_geometryMenu->addAction( qApp->translate( "Command", cmd->getName(0) ), menu ); _registerKeyBinding( cmd, 0, m_geometryMenu, id ); item = new CommandMenuItemT; item->id = id; item->command = cmd; item->arg = 0; item->widget = new CommandWidget(this, m_model, &m_canEdit, cmd, 0 ); connect(id, SIGNAL(triggered(bool)), item->widget, SLOT(activateCommand(bool))); m_primitiveCommands.push_back( item ); } else { QMenu * curMenu = m_geometryMenu; id = insertMenuItem( m_geometryMenu, false, cmd->getPath(), qApp->translate( "Command", cmd->getName(0)), NULL ); //id = curMenu->addAction( qApp->translate( "Command", cmd->getName(0)) ); item = new CommandMenuItemT; item->id = id; item->command = cmd; item->arg = 0; item->widget = new CommandWidget(this, m_model, &m_canEdit, cmd, 0 ); connect(id, SIGNAL(triggered(bool)), item->widget, SLOT(activateCommand(bool))); _registerKeyBinding( cmd, 0, curMenu, id ); log_debug( "adding command '%s' to menus\n", cmd->getName(0) ); m_primitiveCommands.push_back( item ); } } else { m_geometryMenu->addSeparator(); } cmd = m_cmdMgr->getNextCommand(); } } void ViewWindow::fillMruMenu() { m_mruMenu->clear(); for ( unsigned i = 0; i < g_prefs("mru").count(); i++ ) { m_mruMenu->addAction( QString::fromUtf8( g_prefs("mru")[i].stringValue().c_str() ) ); } } void ViewWindow::openMru( QAction * id ) { #ifdef Q_OS_MAC // Open model in a new window if a model is loaded or default scene is modified // (matches global menu bar behavior when no window is open). if ( !emptyWindow() ) { ViewWindow::openModel( id->text().toUtf8() ); } else #endif { openModelInWindow( id->text().toUtf8() ); } } void ViewWindow::fillScriptMruMenu() { m_scriptMruMenu->clear(); for ( unsigned i = 0; i < g_prefs("script_mru").count(); i++ ) { m_scriptMruMenu->addAction( QString::fromUtf8( g_prefs("script_mru")[i].stringValue().c_str() ) ); } } void ViewWindow::openScriptMru( QAction * id ) { runScript( id->text().toUtf8() ); } void ViewWindow::openModelEvent() { #ifdef Q_OS_MAC // Open model in a new window if a model is loaded or default scene is modified // (matches global menu bar behavior when no window is open). if ( !emptyWindow() ) { ViewWindow::openModelDialog(); } else #endif { openModelDialogInWindow(); } } bool ViewWindow::openModel( const char * filename ) { bool opened = false; log_debug( " file: %s\n", filename ); Model::ModelErrorE err; Model * model = new Model(); if ( (err = FilterManager::getInstance()->readFile( model, filename )) == Model::ERROR_NONE) { opened = true; model_show_alloc_stats(); model->setSaved( true ); ViewWindow * win = new ViewWindow( model, NULL ); win->getSaved(); // Just so I don't have a warning prefs_recent_model( filename ); } else { if ( Model::operationFailed( err ) ) { QString reason = modelErrStr( err, model ); reason = QString(filename) + QString(":\n") + reason; msg_error( (const char *) reason.toUtf8() ); } delete model; } return opened; } bool ViewWindow::openModelDialog( const char * openDirectory ) { bool opened = false; list formats = FilterManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats" ) + QString( " (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += QString(" "); } } formatsStr += QString(")"); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = QString( "." ); } if ( openDirectory ) { dir = QString::fromUtf8( openDirectory ); } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setWindowTitle( tr( "Open model file" ) ); d.selectNameFilter( formatsStr ); if ( QDialog::Accepted == d.exec() ) { QStringList files = d.selectedFiles(); if ( files.empty() ) return false; if ( openModel( files[0].toUtf8() ) ) { opened = true; g_prefs( "ui_model_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); } } return opened; } bool ViewWindow::openModelInWindow( const char * filename ) { bool opened = false; log_debug( " file: %s\n", filename ); #ifndef CODE_DEBUG if ( ! m_model->getSaved() ) { int val = QMessageBox::warning( this, tr("Save first?"), tr("Model has been modified\nDo you want to save before closing?"), QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel ); switch ( val ) { case QMessageBox::Yes: m_abortQuit = false; saveModelEvent(); if ( m_abortQuit ) { return false; } break; case QMessageBox::No: break; case QMessageBox::Cancel: return false; break; default: { msg_error( (const char *) tr("Unknown response: Canceling operation").toUtf8() ); } return false; } } #endif // CODE_DEBUG Model::ModelErrorE err; Model * model = new Model(); if ( (err = FilterManager::getInstance()->readFile( model, filename )) == Model::ERROR_NONE) { opened = true; model_show_alloc_stats(); Model * oldModel = m_model; setModel( model ); delete oldModel; frameAllEvent(); prefs_recent_model( filename ); } else { if ( Model::operationFailed( err ) ) { QString reason = modelErrStr( err, model ); reason = QString(filename) + QString(":\n") + reason; msg_error( (const char *) reason.toUtf8() ); } delete model; } return opened; } bool ViewWindow::openModelDialogInWindow( const char * openDirectory ) { bool opened = false; list formats = FilterManager::getInstance()->getAllReadTypes(); QString formatsStr = tr( "All Supported Formats" ) + QString( " (" ); list::iterator it = formats.begin(); while( it != formats.end() ) { formatsStr += QString( (*it).c_str() ); it++; if ( it != formats.end() ) { formatsStr += QString(" "); } } formatsStr += QString(")"); QString dir = QString::fromUtf8( g_prefs( "ui_model_dir" ).stringValue().c_str() ); if ( dir.isEmpty() ) { dir = "."; } if ( openDirectory ) { dir = openDirectory; } QFileDialog d(NULL, QString(""), dir, formatsStr + QString(";; ") + tr( "All Files (*)" ) ); d.setWindowTitle( tr( "Open model file" ) ); d.selectNameFilter( formatsStr ); if ( QDialog::Accepted == d.exec() ) { QStringList files = d.selectedFiles(); if ( files.empty() ) return false; if ( openModelInWindow( files[0].toUtf8() ) ) { opened = true; g_prefs( "ui_model_dir" ) = (const char *) d.directory().absolutePath().toUtf8(); } } return opened; } void ViewWindow::invalidateModelTextures() { ViewWindowList::iterator windowIter; Model * model; DecalManager * mgr = DecalManager::getInstance(); for( windowIter = _winList.begin(); windowIter != _winList.end(); windowIter++ ) { model = (*windowIter)->getModel(); model->invalidateTextures(); mgr->modelUpdated( model ); } } void ViewWindow::quitEvent() { saveDockPositions(); if ( ViewWindow::closeAllWindows() ) { qApp->quit(); } } void ViewWindow::pluginWindowEvent() { // pluginWin will delete itself view WDestructiveClose PluginWindow * pluginWin = new PluginWindow(); pluginWin->show(); } void ViewWindow::backgroundWindowEvent() { // pluginWin will delete itself view WDestructiveClose BackgroundWin * win = new BackgroundWin( m_model ); win->show(); } void ViewWindow::newModelEvent() { ViewWindow * win = new ViewWindow( new Model, NULL ); win->getSaved(); // Just so I don't have a warning } void ViewWindow::savedTimeoutCheck() { updateCaption(); } void ViewWindow::saveDockPositions() { QString dockFile( getMm3dHomeDirectory().c_str() ); dockFile += "/"; dockFile += DOCK_FILENAME; QFile fp( dockFile ); if ( fp.open( QIODevice::WriteOnly ) ) { { // Must go out of scope before fp is closed. QDataStream stream(&fp); stream << this->saveState( DOCK_VERSION ); } fp.close(); } } void ViewWindow::loadDockPositions() { QString dockFile( getMm3dHomeDirectory().c_str() ); dockFile += "/"; dockFile += DOCK_FILENAME; QFile fp( dockFile ); if ( fp.open( QIODevice::ReadOnly ) ) { { // Must go out of scope before fp is closed. QDataStream stream(&fp); QByteArray state; stream >> state; this->restoreState( state, DOCK_VERSION ); } fp.close(); } } void ViewWindow::updateCaption() { QString caption = QString( "Misfit Model 3D: " ); if ( m_model ) { caption += m_model->getSaved() ? QString("") : QString("* "); const char * filename = m_model->getFilename(); if ( filename && filename[0] ) { std::string fullName; std::string fullPath; std::string baseName; normalizePath( filename, fullName, fullPath, baseName ); caption += baseName.c_str(); } else { caption += tr( "[unnamed]", "For filename in title bar (if not set)" ); } } setWindowTitle( caption ); } mm3d-master/src/implui/viewwin.h000066400000000000000000000226571324021725400171520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __VIEWWIN_H #define __VIEWWIN_H #include "config.h" #include "contextpanelobserver.h" #include using std::list; class QVBoxLayout; class QMenuBar; class QMenu; class QToolBar; class QTimer; class ViewPanel; class ContextPanel; class BoolPanel; class ProjectionWin; class TextureCoord; class TransformWindow; class StatusBar; class Model; class Command; class Tool; class Script; class AnimWidget; class AnimWindow; class QToolButton; class Toolbox; class CommandManager; class QContextMenuEvent; class QCloseEvent; class QResizeEvent; #include #include class CommandWidget : public QObject { Q_OBJECT public: CommandWidget( QObject * parent, Model * model, bool * canEdit, Command * cmd, int index ); virtual ~CommandWidget(); public slots: void setModel( Model * m ); void activateCommand( bool ); private: Model * m_model; bool * m_canEdit; Command * m_cmd; int m_index; }; class ViewWindow : public QMainWindow, public ContextPanelObserver { Q_OBJECT public: ViewWindow( Model * model, QWidget * parent = NULL ); virtual ~ViewWindow(); static bool closeAllWindows(); static bool openModelInEmptyWindow( const char * filename ); static bool openModel( const char * filename ); static bool openModelDialog( const char * openDirectory = NULL ); static void invalidateModelTextures(); void setModel( Model * model ); bool openModelInWindow( const char * filename ); bool openModelDialogInWindow( const char * openDirectory = NULL ); bool emptyWindow(); bool getSaved(); bool getAbortQuit() { return m_abortQuit; }; void setAbortQuit( bool o ) { m_abortQuit = o; }; Model *getModel() { return m_model; }; // ContextPanelObserver methods void showProjectionEvent(); signals: void modelChanged( Model * m ); public slots: void helpNowEvent(); void saveModelEvent(); void saveModelAsEvent(); void exportModelEvent(); void exportSelectedEvent(); void mergeModelsEvent(); void mergeAnimationsEvent(); void scriptEvent(); void runScript( const char * filename ); void frameAllEvent(); void frameSelectedEvent(); void showContextEvent(); void renderBadEvent(); void noRenderBadEvent(); void renderSelectionEvent(); void noRenderSelectionEvent(); void renderBackface(); void noRenderBackface(); void renderProjections(); void noRenderProjections(); void boneJointHide(); void boneJointLines(); void boneJointBones(); void viewportSettingsEvent(); void groupWindowEvent(); void textureWindowEvent(); void groupCleanWindowEvent(); void textureCoordEvent(); void paintTextureEvent(); void projectionWindowEvent(); void transformWindowEvent(); void metaWindowEvent(); void boolWindowEvent(); void reloadTexturesEvent(); void buttonToggled( bool on ); void toolActivated( QAction * id ); void scriptActivated( QAction * id ); void animSetWindowEvent(); void animExportWindowEvent(); void animSetRotEvent(); void animSetTransEvent(); void animCopyFrameEvent(); void animPasteFrameEvent(); void animClearFrameEvent(); void animCopySelectedEvent(); void animPasteSelectedEvent(); void startAnimationMode(); void stopAnimationMode(); void animationModeOn(); void animationModeOff(); void contextPanelHidden(); void editDisableEvent(); void editEnableEvent(); void undoRequest(); void redoRequest(); void snapToSelectedEvent( QAction * snapTo ); void fillMruMenu(); void openMru( QAction * id ); void fillScriptMruMenu(); void openScriptMru( QAction * id ); void openModelEvent(); void newModelEvent(); void quitEvent(); void pluginWindowEvent(); void backgroundWindowEvent(); void helpWindowEvent(); void aboutWindowEvent(); void licenseWindowEvent(); void savedTimeoutCheck(); // influences slots void jointWinEvent(); void jointAssignSelectedToJoint(); void jointAutoAssignSelected(); void jointRemoveInfluencesFromSelected(); void jointRemoveInfluenceJoint(); void jointMakeSingleInfluence(); void jointSelectInfluenceJoints(); void jointSelectInfluencedVertices(); void jointSelectInfluencedPoints(); void jointSelectUnassignedVertices(); void jointSelectUnassignedPoints(); protected: void saveModelInternal( Model * model, bool exportModel = false ); void contextMenuEvent( QContextMenuEvent * e ); void saveDockPositions(); void loadDockPositions(); void updateCaption(); void initializeToolbox(); void initializeCommands(); void closeEvent( QCloseEvent * e ); void resizeEvent( QResizeEvent * ); // returns id in menu QAction * insertMenuItem( QMenu * parentMenu, bool isTool, const QString & path, const QString & name, QMenu * subMenu ); struct _ToolMenuItem_t { QAction * id; ::Tool * tool; int arg; }; typedef struct _ToolMenuItem_t ToolMenuItemT; typedef list< ToolMenuItemT * > ToolMenuItemList; typedef struct _CommandMenuItem_t { QAction * id; Command * command; CommandWidget * widget; int arg; } CommandMenuItemT; typedef list< CommandMenuItemT * > CommandMenuItemList; typedef struct _MenuItem_t { QString text; QMenu * menu; } MenuItemT; typedef list< MenuItemT > MenuItemList; QMenuBar * m_menuBar; QMenu * m_fileMenu; QMenu * m_viewMenu; QMenu * m_renderMenu; QMenu * m_toolMenu; QMenu * m_modelMenu; QMenu * m_geometryMenu; QMenu * m_materialsMenu; QMenu * m_jointsMenu; QMenu * m_animMenu; QMenu * m_scriptMenu; QMenu * m_helpMenu; QMenu * m_mruMenu; QMenu * m_scriptMruMenu; QMenu * m_snapMenu; QToolBar * m_toolBar; ViewPanel * m_viewPanel; ContextPanel * m_contextPanel; BoolPanel * m_boolPanel; ProjectionWin * m_projectionWin; TextureCoord * m_textureCoordWin; TransformWindow * m_transformWin; StatusBar * m_statusBar; Model * m_model; AnimWindow * m_animWin; AnimWidget * m_animWidget; QAction * m_snapToGrid; QAction * m_snapToVertex; QAction * m_animSetsItem; QAction * m_animExportItem; QAction * m_animSetRotItem; QAction * m_animSetTransItem; QAction * m_animCopyFrame; QAction * m_animPasteFrame; QAction * m_animCopySelected; QAction * m_animPasteSelected; QAction * m_animClearFrame; QAction * m_startAnimItem; QAction * m_stopAnimItem; QAction * m_showContext; QAction * m_3dWire; QAction * m_3dFlat; QAction * m_3dSmooth; QAction * m_3dTexture; QAction * m_3dAlpha; QAction * m_canvasWire; QAction * m_canvasFlat; QAction * m_canvasSmooth; QAction * m_canvasTexture; QAction * m_canvasAlpha; QAction * m_view1; QAction * m_view1x2; QAction * m_view2x1; QAction * m_view2x2; QAction * m_view2x3; QAction * m_view3x2; QAction * m_view3x3; QAction * m_renderBadItem; QAction * m_noRenderBadItem; QAction * m_renderSelectionItem; QAction * m_noRenderSelectionItem; QAction * m_hideJointsItem; QAction * m_drawJointLinesItem; QAction * m_drawJointBonesItem; QAction * m_renderBackface; QAction * m_noRenderBackface; QAction * m_renderProjections; QAction * m_noRenderProjections; bool m_abortQuit; CommandMenuItemList m_primitiveCommands; CommandMenuItemList m_groupCommands; ToolMenuItemList m_tools; MenuItemList m_menuItems; CommandManager * m_cmdMgr; // Moved from toolwidget int m_toolCount; Toolbox * m_toolbox; ::Tool ** m_toolList; QAction ** m_toolButtons; QAction * m_last; ::Tool * m_currentTool; bool m_canEdit; QTimer * m_savedTimer; }; #endif // __VIEWWIN_H mm3d-master/src/implui/viewwin_influences.cc000066400000000000000000000220121324021725400215040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "viewwin.h" #include "viewpanel.h" #include "model.h" #include "modelstatus.h" #include "jointwin.h" #include "autoassignjointwin.h" #include "log.h" void ViewWindow::jointWinEvent() { // this calls operationComplete and updates the model itself JointWin * win = new JointWin( m_model ); win->show(); } void ViewWindow::jointAssignSelectedToJoint() { std::list j; std::list::iterator jit; m_model->getSelectedBoneJoints( j ); if ( !j.empty() ) { list::iterator it; list vertList; m_model->getSelectedVertices( vertList ); list pointList; m_model->getSelectedPoints( pointList ); log_debug( "assigning %d vertices and %d points to joints\n", vertList.size(), pointList.size() ); QString str = tr( "assigning %1 vertices and %2 points to joints").arg(vertList.size()).arg( pointList.size() ); model_status( m_model, StatusNormal, STATUSTIME_SHORT, "%s", (const char *) str.toUtf8() ); for ( it = vertList.begin(); it != vertList.end(); it++ ) { for ( jit = j.begin(); jit != j.end(); jit++ ) { double w = m_model->calculateVertexInfluenceWeight( *it, *jit ); m_model->addVertexInfluence( *it, *jit, Model::IT_Auto, w ); } } for ( it = pointList.begin(); it != pointList.end(); it++ ) { for ( jit = j.begin(); jit != j.end(); jit++ ) { double w = m_model->calculatePointInfluenceWeight( *it, *jit ); m_model->addPointInfluence( *it, *jit, Model::IT_Auto, w ); } } m_model->operationComplete( tr("Assign Selected to Joint").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } else { model_status( m_model, StatusError, STATUSTIME_LONG, tr("You must have at least one bone joint selected.").toUtf8() ); } } void ViewWindow::jointAutoAssignSelected() { std::list p; std::list::iterator pit; m_model->getSelectedPositions( p ); if ( !p.empty() ) { AutoAssignJointWin win( m_model, this ); if ( win.exec() ) { double sensitivity = ((double) win.getSensitivity() ) / 100.0; bool selected = win.getSelected(); log_debug( "auto-assigning %p vertices and points to joints\n", p.size() ); for ( pit = p.begin(); pit != p.end(); pit++ ) { m_model->autoSetPositionInfluences( *pit, sensitivity, selected ); } m_model->operationComplete( tr("Auto-Assign Selected to Bone Joints").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } } else { model_status( m_model, StatusError, STATUSTIME_LONG, tr("You must have at least one vertex or point selected.").toUtf8() ); } } void ViewWindow::jointRemoveInfluencesFromSelected() { std::list< Model::Position > posList; std::list< Model::Position >::iterator it; m_model->getSelectedPositions( posList ); for ( it = posList.begin(); it != posList.end(); it++ ) { m_model->removeAllPositionInfluences( *it ); } m_model->operationComplete( tr("Remove All Influences from Selected").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointRemoveInfluenceJoint() { std::list jointList; std::list::iterator it; unsigned vcount = m_model->getVertexCount(); unsigned pcount = m_model->getPointCount(); m_model->getSelectedBoneJoints( jointList ); for ( it = jointList.begin(); it != jointList.end(); it++ ) { for ( unsigned v = 0; v < vcount; v++ ) { m_model->removeVertexInfluence( v, *it ); } for ( unsigned p = 0; p < pcount; p++ ) { m_model->removePointInfluence( p, *it ); } } m_model->operationComplete( tr("Remove Joint from Influencing").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointMakeSingleInfluence() { unsigned vcount = m_model->getVertexCount(); unsigned pcount = m_model->getPointCount(); int bcount = m_model->getBoneJointCount(); for ( unsigned v = 0; v < vcount; v++ ) { int joint = m_model->getPrimaryVertexInfluence( v ); if ( joint >= 0 ) { for ( int b = 0; b < bcount; b++ ) { if ( b != joint ) { m_model->removeVertexInfluence( v, b ); } } } } for ( unsigned p = 0; p < pcount; p++ ) { int joint = m_model->getPrimaryPointInfluence( p ); if ( joint >= 0 ) { for ( int b = 0; b < bcount; b++ ) { if ( b != joint ) { m_model->removePointInfluence( p, b ); } } } } m_model->operationComplete( tr("Convert To Single Influence").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointSelectUnassignedVertices() { m_model->unselectAllVertices(); m_model->beginSelectionDifference(); unsigned vcount = m_model->getVertexCount(); for ( unsigned v = 0; v < vcount; v++ ) { Model::InfluenceList l; m_model->getVertexInfluences( v, l ); if ( l.empty() ) { m_model->selectVertex( v ); } } m_model->endSelectionDifference(); m_model->operationComplete( tr("Select Unassigned Vertices").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointSelectUnassignedPoints() { m_model->unselectAllVertices(); m_model->beginSelectionDifference(); unsigned pcount = m_model->getPointCount(); for ( unsigned p = 0; p < pcount; p++ ) { Model::InfluenceList l; m_model->getPointInfluences( p, l ); if ( l.empty() ) { m_model->selectPoint( p ); } } m_model->endSelectionDifference(); m_model->operationComplete( tr("Select Unassigned Points").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointSelectInfluenceJoints() { m_model->beginSelectionDifference(); Model::InfluenceList ilist; Model::InfluenceList::iterator iit; list< Model::Position > posList; list< Model::Position >::iterator it; m_model->getSelectedPositions( posList ); for ( it = posList.begin(); it != posList.end(); it++ ) { m_model->getPositionInfluences( *it, ilist ); for ( iit = ilist.begin(); iit != ilist.end(); iit++ ) { m_model->selectBoneJoint( (*iit).m_boneId ); } } m_model->endSelectionDifference(); m_model->operationComplete( tr("Select Joint Influences").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointSelectInfluencedVertices() { m_model->beginSelectionDifference(); Model::InfluenceList ilist; Model::InfluenceList::iterator iit; list< int > jointList; list< int >::iterator it; unsigned vcount = m_model->getVertexCount(); m_model->getSelectedBoneJoints( jointList ); for ( it = jointList.begin(); it != jointList.end(); it++ ) { for ( unsigned v = 0; v < vcount; v++ ) { m_model->getVertexInfluences( v, ilist ); for ( iit = ilist.begin(); iit != ilist.end(); iit++ ) { if ( (*iit).m_boneId == *it ) { m_model->selectVertex( v ); } } } } m_model->endSelectionDifference(); m_model->operationComplete( tr("Select Influences Vertices").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } void ViewWindow::jointSelectInfluencedPoints() { m_model->beginSelectionDifference(); Model::InfluenceList ilist; Model::InfluenceList::iterator iit; list< int > jointList; list< int >::iterator it; unsigned pcount = m_model->getBoneJointCount(); m_model->getSelectedBoneJoints( jointList ); for ( it = jointList.begin(); it != jointList.end(); it++ ) { for ( unsigned p = 0; p < pcount; p++ ) { m_model->getPointInfluences( p, ilist ); for ( iit = ilist.begin(); iit != ilist.end(); iit++ ) { if ( (*iit).m_boneId == *it ) { m_model->selectPoint( p ); } } } } m_model->endSelectionDifference(); m_model->operationComplete( tr("Select Influenced Points").toUtf8() ); m_viewPanel->modelUpdatedEvent(); } mm3d-master/src/libmm3d/000077500000000000000000000000001324021725400153255ustar00rootroot00000000000000mm3d-master/src/libmm3d/Makefile.am000066400000000000000000000040221324021725400173570ustar00rootroot00000000000000noinst_LIBRARIES = libmm3d.a libmm3d_HFILES = \ binutil.h \ bsptree.h \ cal3dfilter.h \ cmdlinemgr.h \ cobfilter.h \ datadest.h \ filedatadest.h \ memdatadest.h \ datasource.h \ filedatasource.h \ memdatasource.h \ drawcontext.h \ dxffilter.h \ endianconfig.h \ file_closer.h \ filefactory.h \ filtermgr.h \ glheaders.h \ glmath.h \ local_array.h \ local_ptr.h \ log.h \ lwofilter.h \ md2filter-anorms.h \ md2filter.h \ md3filter.h \ mesh.h \ misc.h \ mlocale.h \ mm3dconfig.h \ mm3dfilter.h \ mm3dfilter_ref.h \ mm3dport.h \ mm3dreg.h \ mm3dtypes.h \ model.h \ modelfilter.h \ modelstatus.h \ modelundo.h \ modelutil.h \ ms3dfilter.h \ msg.h \ objfilter.h \ pcxtex.h \ raii.h \ rawtex.h \ release_ptr.h \ sorted_list.h \ texmgr.h \ texscale.h \ texture.h \ tgatex.h \ triprim.h \ translate.h \ txtfilter.h \ undo.h \ undomgr.h \ util.h \ weld.h libmm3d_a_SOURCES = \ bsptree.cc \ cal3dfilter.cc \ cmdlinemgr.cc \ cobfilter.cc \ datadest.cc \ filedatadest.cc \ memdatadest.cc \ datasource.cc \ filedatasource.cc \ memdatasource.cc \ dxffilter.cc \ filefactory.cc \ filtermgr.cc \ glmath.cc \ log.cc \ lwofilter.cc \ mesh.cc \ misc.cc \ mlocale.cc \ model.cc model_anim.cc model_bool.cc model_copy.cc model_draw.cc model_group.cc model_influence.cc model_inner.cc model_insert.cc model_meta.cc model_ops.cc model_print.cc model_proj.cc model_select.cc model_texture.cc \ modelfilter.cc \ modelstatus.cc \ modelundo.cc \ modelutil.cc \ md2filter.cc \ md3filter.cc \ mm3dfilter.cc \ mm3dfilter_ref.cc \ mm3dreg.cc \ mm3dport.cc \ ms3dfilter.cc \ msg.cc \ objfilter.cc \ texmgr.cc \ texscale.cc \ texture.cc \ triprim.cc \ translate.cc \ undo.cc \ undomgr.cc \ weld.cc \ pcxtex.cc \ rawtex.cc \ tgatex.cc \ txtfilter.cc \ $(libmm3d_HFILES) AM_CPPFLAGS = $(CORE_PROFILE) $(COVFLAGS) -Wall -I.. -DMM3D_EDIT $(all_includes) $(GL_CFLAGS) wc: wc `ls *.h *.cpp *.cc *.y *.l 2> /dev/null | grep -v moc.cc | grep -v "\.base\." ` | sort -n CLEANFILES = *.gcno *.gcda mm3d-master/src/libmm3d/binutil.h000066400000000000000000000022351324021725400171460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BINUTIL_H #define __BINUTIL_H template bool bin_read( T & dest, uint8_t * & src, unsigned & len ) { if ( len >= sizeof( T ) ) { dest = * (T*) src; src += sizeof( T ); len -= sizeof( T ); return true; } else { return false; } } #endif // __BINUTIL_H mm3d-master/src/libmm3d/bsptree.cc000066400000000000000000000461551324021725400173130ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include #include #include #include "glheaders.h" #include "bsptree.h" #include "glmath.h" #include "log.h" #include "model.h" // Yes, it's hackish std::list< BspTree::Poly * > BspTree::Poly::s_recycle; std::list< BspTree::Node * > BspTree::Node::s_recycle; int BspTree::Poly::s_allocated = 0; int BspTree::Node::s_allocated = 0; void normalize( float * val ) { float mag = 0.0f; int t; for ( t = 0; t < 3; t++ ) { mag += val[t] * val[t]; } mag = sqrt( mag ); for ( t = 0; t < 3; t++ ) { val[t] = val[t] / mag; } } float dot_product( float * val1, float * val2 ) { return ( val1[0] * val2[0] ) + ( val1[1] * val2[1] ) + ( val1[2] * val2[2] ); } bool float_equiv( float rhs, float lhs ) { if ( fabs( rhs - lhs ) < 0.0001f ) { return true; } else { return false; } } static void _setMaterial( DrawingContext * context, int texture, Model::Material * material ) { glMaterialfv( GL_FRONT, GL_AMBIENT, material->m_ambient ); glMaterialfv( GL_FRONT, GL_DIFFUSE, material->m_diffuse ); glMaterialfv( GL_FRONT, GL_SPECULAR, material->m_specular ); glMaterialfv( GL_FRONT, GL_EMISSION, material->m_emissive ); glMaterialf( GL_FRONT, GL_SHININESS, material->m_shininess ); context->m_currentTexture = texture; if ( material->m_type == Model::Material::MATTYPE_TEXTURE ) { glBindTexture( GL_TEXTURE_2D, context->m_matTextures[ context->m_currentTexture ] ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, material->m_sClamp ? GL_CLAMP : GL_REPEAT); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, material->m_tClamp ? GL_CLAMP : GL_REPEAT); } } int BspTree::Poly::s_nextId = 0; void BspTree::Poly::calculateNormal() { float A = coord[0][1] * (coord[1][2] - coord[2][2]) + coord[1][1] * (coord[2][2] - coord[0][2]) + coord[2][1] * (coord[0][2] - coord[1][2]); float B = coord[0][2] * (coord[1][0] - coord[2][0]) + coord[1][2] * (coord[2][0] - coord[0][0]) + coord[2][2] * (coord[0][0] - coord[1][0]); float C = coord[0][0] * (coord[1][1] - coord[2][1]) + coord[1][0] * (coord[2][1] - coord[0][1]) + coord[2][0] * (coord[0][1] - coord[1][1]); float len = sqrt((A * A) + (B * B) + (C * C)); norm[0] = A / len; norm[1] = B / len; norm[2] = C / len; calculateD(); //printf( "normal: %f %f %f\n", norm[0], norm[1], norm[2] ); //printf( "d: %f\n", d ); } void BspTree::Poly::calculateD() { d = dot_product( coord[0], norm ); } void BspTree::Poly::intersection( float * p1, float * p2, float * po, float & place ) { float interval = 0.25; float dtemp = 0.0f; place = 0.5f; bool greater = false; if ( dot_product( p2, norm ) > d ) { greater = true; } if ( dot_product( p1, norm ) > d ) { if ( greater ) { //printf( "no intersection!\n" ); return; } } else { if ( !greater ) { //printf( "no intersection!\n" ); return; } } float diff[3]; float oldPlace = place; diff[0] = p2[0] - p1[0]; diff[1] = p2[1] - p1[1]; diff[2] = p2[2] - p1[2]; do { po[0] = diff[0] * place + p1[0]; po[1] = diff[1] * place + p1[1]; po[2] = diff[2] * place + p1[2]; dtemp = dot_product( po, norm ); oldPlace = place; if ( greater ) { place += ( dtemp > d ) ? -interval : interval; } else { place += ( dtemp > d ) ? interval : -interval; } interval = interval * 0.5f; } while ( !float_equiv( d, dtemp ) ); place = oldPlace; } void BspTree::Poly::render( DrawingContext * context ) { //printf( "render triangle %d\n", id ); if ( context->m_currentTexture != texture ) { glEnd(); _setMaterial( context, texture, static_cast< Model::Material *>( material ) ); glBegin( GL_TRIANGLES ); } Model::Triangle * tri = static_cast< Model::Triangle *>( triangle ); if ( tri->m_visible ) { for ( int i = 0; i < 3; i++ ) { glTexCoord2f( s[ i ], t[ i ] ); glNormal3fv( drawNormals[i] ); glVertex3fv( coord[i] ); } } } void BspTree::Poly::print() { //printf( "Poly %d\n", id ); //printf( " coord[0] = %f %f %f\n", coord[0][0], coord[0][1], coord[0][2] ); //printf( " coord[1] = %f %f %f\n", coord[1][0], coord[1][1], coord[1][2] ); //printf( " coord[2] = %f %f %f\n", coord[2][0], coord[2][1], coord[2][2] ); //printf( " n = %f %f %f\n", norm[0], norm[1], norm[2] ); } void BspTree::addPoly( BspTree::Poly * p ) { Node * n = Node::get(); n->self = p; if ( m_root == NULL ) { m_root = n; } else { m_root->addChild( n ); } } void BspTree::render( float * point, DrawingContext * context ) { if ( m_root ) { _setMaterial( context, m_root->self->texture, static_cast< Model::Material *>( m_root->self->material ) ); glEnable( GL_TEXTURE_2D ); glBegin( GL_TRIANGLES ); m_root->render( point, context ); glEnd(); } } void BspTree::clear() { if ( m_root ) { m_root->release(); m_root = NULL; } } BspTree::Poly * BspTree::Poly::get() { if ( !s_recycle.empty() ) { Poly * n = s_recycle.front(); s_recycle.pop_front(); return n; } else { return new Poly; } } void BspTree::Poly::release() { s_recycle.push_front( this ); } BspTree::Node * BspTree::Node::get() { if ( !s_recycle.empty() ) { Node * n = s_recycle.front(); s_recycle.pop_front(); n->self = NULL; n->left = NULL; n->right = NULL; return n; } else { return new Node; } } void BspTree::Node::release() { if ( left ) { left->release(); } if ( self ) { self->release(); } if ( right ) { right->release(); } s_recycle.push_front( this ); } void BspTree::Node::splitNodes( int idx1, int idx2, int idx3, float * p1, float * p2, BspTree::Node * n1, BspTree::Node * n2, const float & place1, const float & place2 ) { n1->self = Poly::get(); //printf( "split node poly: %d\n", n1->self->id ); for ( int i = 0; i < 3; i++ ) { n1->self->coord[0][i] = p1[i]; n1->self->coord[1][i] = self->coord[idx2][i]; n1->self->coord[2][i] = self->coord[idx3][i]; n1->self->drawNormals[0][i] = self->norm[i]; n1->self->drawNormals[1][i] = self->drawNormals[idx2][i]; n1->self->drawNormals[2][i] = self->drawNormals[idx3][i]; } n1->self->s[0] = (self->s[ idx2 ] - self->s[ idx1 ]) * place1 + self->s[ idx1 ]; n1->self->s[1] = self->s[ idx2 ]; n1->self->s[2] = self->s[ idx3 ]; n1->self->t[0] = (self->t[ idx2 ] - self->t[ idx1 ]) * place1 + self->t[ idx1 ]; n1->self->t[1] = self->t[ idx2 ]; n1->self->t[2] = self->t[ idx3 ]; n1->self->calculateNormal(); n1->self->texture = self->texture; n1->self->triangle = self->triangle; n1->self->material = self->material; n2->self = Poly::get(); //printf( "split node poly: %d\n", n2->self->id ); for ( int i = 0; i < 3; i++ ) { n2->self->coord[0][i] = p1[i]; n2->self->coord[1][i] = self->coord[idx3][i]; n2->self->coord[2][i] = p2[i]; n2->self->drawNormals[0][i] = self->norm[i]; n2->self->drawNormals[1][i] = self->drawNormals[idx3][i]; n2->self->drawNormals[2][i] = self->norm[i]; } n2->self->s[0] = (self->s[ idx2 ] - self->s[ idx1 ]) * place1 + self->s[ idx1 ]; n2->self->s[1] = self->s[ idx3 ]; n2->self->s[2] = (self->s[ idx3 ] - self->s[ idx1 ]) * place2 + self->s[ idx1 ]; n2->self->t[0] = (self->t[ idx2 ] - self->t[ idx1 ]) * place1 + self->t[ idx1 ]; n2->self->t[1] = self->t[ idx3 ]; n2->self->t[2] = (self->t[ idx3 ] - self->t[ idx1 ]) * place2 + self->t[ idx1 ]; n2->self->calculateNormal(); n2->self->texture = self->texture; n2->self->triangle = self->triangle; n2->self->material = self->material; for ( int i = 0; i < 3; i++ ) { self->coord[idx2][i] = p1[i]; self->coord[idx3][i] = p2[i]; self->drawNormals[idx2][i] = self->norm[i]; self->drawNormals[idx3][i] = self->norm[i]; } self->s[idx2] = (self->s[ idx2 ] - self->s[ idx1 ]) * place1 + self->s[ idx1 ]; self->s[idx3] = (self->s[ idx3 ] - self->s[ idx1 ]) * place2 + self->s[ idx1 ]; self->t[idx2] = (self->t[ idx2 ] - self->t[ idx1 ]) * place1 + self->t[ idx1 ]; self->t[idx3] = (self->t[ idx3 ] - self->t[ idx1 ]) * place2 + self->t[ idx1 ]; self->calculateD(); } void BspTree::Node::splitNode( int idx1, int idx2, int idx3, float * p1, BspTree::Node * n1, const float & place ) { n1->self = Poly::get(); //printf( "split node poly: %d\n", n1->self->id ); for ( int i = 0; i < 3; i++ ) { n1->self->coord[0][i] = self->coord[idx1][i]; n1->self->coord[1][i] = self->coord[idx2][i]; n1->self->coord[2][i] = p1[i]; n1->self->drawNormals[0][i] = self->drawNormals[idx1][i]; n1->self->drawNormals[1][i] = self->drawNormals[idx2][i]; n1->self->drawNormals[2][i] = self->norm[i]; } n1->self->s[0] = self->s[ idx1 ]; n1->self->s[1] = self->s[ idx2 ]; n1->self->s[2] = (self->s[ idx3 ] - self->s[ idx2 ]) * place + self->s[ idx2 ]; n1->self->t[0] = self->t[ idx1 ]; n1->self->t[1] = self->t[ idx2 ]; n1->self->t[2] = (self->t[ idx3 ] - self->t[ idx2 ]) * place + self->t[ idx2 ]; n1->self->calculateNormal(); n1->self->texture = self->texture; n1->self->triangle = self->triangle; n1->self->material = self->material; for ( int i = 0; i < 3; i++ ) { self->coord[idx2][i] = p1[i]; self->drawNormals[idx2][i] = self->norm[i]; } self->s[idx2] = (self->s[ idx3 ] - self->s[ idx2 ]) * place + self->s[ idx2 ]; self->t[idx2] = (self->t[ idx3 ] - self->t[ idx2 ]) * place + self->t[ idx2 ]; self->calculateD(); } void BspTree::Node::addChild( Node * n ) { float d1 = dot_product( self->norm, n->self->coord[0] ); float d2 = dot_product( self->norm, n->self->coord[1] ); float d3 = dot_product( self->norm, n->self->coord[2] ); int i1 = 0; int i2 = 0; int i3 = 0; if ( !float_equiv( d1, self->d ) ) i1 = ( d1 < self->d ) ? -1 : 1; if ( !float_equiv( d2, self->d ) ) i2 = ( d2 < self->d ) ? -1 : 1; if ( !float_equiv( d3, self->d ) ) i3 = ( d3 < self->d ) ? -1 : 1; //printf( "self d = %f\n", self->d ); //printf( "addChild d = %f %f %f\n", d1, d2, d3 ); //printf( "addChild i = %d %d %d\n", i1, i2, i3 ); // This will catch co-plane also... which should be fine if ( i1 <= 0 && i2 <= 0 && i3 <= 0 ) { //printf( "add right\n" ); if ( left ) { left->addChild( n ); } else { left = n; } return; } if ( i1 >= 0 && i2 >= 0 && i3 >= 0 ) { //printf( "add left\n" ); if ( right ) { right->addChild( n ); } else { right = n; } return; } //printf( "split\n" ); float p1[3]; float p2[3]; float place1 = 0.0f; float place2 = 0.0f; if ( i1 == 0 || i2 == 0 || i3 == 0 ) { // one of the vertices is on the plane //printf( "split on vertex\n" ); Node * n1 = Node::get(); if ( i1 == 0 ) { self->intersection( n->self->coord[1], n->self->coord[2], p1, place1 ); n->splitNode( 0, 1, 2, p1, n1, place1 ); if ( i2 < 0 ) { if ( right ) addChild( n ); else right = n; if ( left ) left->addChild( n1 ); else left = n1; } else { if ( right ) addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } } else if ( i2 == 0 ) { self->intersection( n->self->coord[2], n->self->coord[0], p1, place1 ); n->splitNode( 1, 2, 0, p1, n1, place1 ); if ( i1 < 0 ) { if ( right ) addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } else { if ( right ) addChild( n ); else right = n; if ( left ) left->addChild( n1 ); else left = n1; } } else if ( i3 == 0 ) { self->intersection( n->self->coord[0], n->self->coord[1], p1, place1 ); n->splitNode( 2, 0, 1, p1, n1, place1 ); if ( i1 < 0 ) { if ( right ) addChild( n ); else right = n; if ( left ) left->addChild( n1 ); else left = n1; } else { if ( right ) addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } } } else { Node * n1 = Node::get(); Node * n2 = Node::get(); if ( i1 == i2 ) { //printf( "split 1/2\n" ); self->intersection( n->self->coord[2], n->self->coord[0], p1, place1 ); self->intersection( n->self->coord[2], n->self->coord[1], p2, place2 ); //printf( "split at %f %f %f\n", p1[0], p1[1], p1[2] ); //printf( "split at %f %f %f\n", p2[0], p2[1], p2[2] ); n->splitNodes( 2, 0, 1, p1, p2, n1, n2, place1, place2 ); if ( i3 < 0 ) { n1->left = n2; if ( right ) right->addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } else { n1->right = n2; if ( left ) left->addChild( n1 ); else left = n1; if ( right ) right->addChild( n ); else right = n; } } else if ( i1 == i3 ) { //printf( "split 1/3\n" ); self->intersection( n->self->coord[1], n->self->coord[2], p1, place1 ); self->intersection( n->self->coord[1], n->self->coord[0], p2, place2 ); //printf( "split at %f %f %f\n", p1[0], p1[1], p1[2] ); //printf( "split at %f %f %f\n", p2[0], p2[1], p2[2] ); n->splitNodes( 1, 2, 0, p1, p2, n1, n2, place1, place2 ); if ( i2 < 0 ) { n1->left = n2; if ( right ) right->addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } else { n1->right = n2; if ( left ) left->addChild( n1 ); else left = n1; if ( right ) right->addChild( n ); else right = n; } } else if ( i2 == i3 ) { self->intersection( n->self->coord[0], n->self->coord[1], p1, place1 ); self->intersection( n->self->coord[0], n->self->coord[2], p2, place2 ); n->splitNodes( 0, 1, 2, p1, p2, n1, n2, place1, place2 ); if ( i1 < 0 ) { n1->left = n2; if ( right ) right->addChild( n1 ); else right = n1; if ( left ) left->addChild( n ); else left = n; } else { n1->right = n2; if ( left ) left->addChild( n1 ); else left = n1; if ( right ) right->addChild( n ); else right = n; } } } } void BspTree::Node::render( float * point, DrawingContext * context ) { float d = dot_product( self->norm, point ); if ( d < self->d ) { if ( right ) { right->render( point, context ); } self->render( context ); if ( left ) { left->render( point, context ); } } else { if ( left ) { left->render( point, context ); } self->render( context ); if ( right ) { right->render( point, context ); } } } void BspTree::Poly::stats() { log_debug( "BspTree::Poly: %d/%d\n", s_recycle.size(), s_allocated ); } void BspTree::Node::stats() { log_debug( "BspTree::Node: %d/%d\n", s_recycle.size(), s_allocated ); } int BspTree::Poly::flush() { int c = 0; std::list::iterator it = s_recycle.begin(); while ( it != s_recycle.end() ) { delete *it; it++; c++; } s_recycle.clear(); return c; } int BspTree::Node::flush() { int c = 0; std::list::iterator it = s_recycle.begin(); while ( it != s_recycle.end() ) { delete *it; it++; c++; } s_recycle.clear(); return c; } #if 0 int main( int argc, char * argv[] ) { char input[128]; BspTree tree; while ( fgets( input, sizeof(input), stdin ) ) { float coord[0][3]; float coord[1][3]; float coord[2][3]; if ( input[0] == 'c' ) { printf( "camera\n" ); if ( sscanf(&input[1], "%f %f %f", &coord[0][0], &coord[0][1], &coord[0][2] ) == 3 ) { printf( "got camera point\n" ); tree.render( coord[0] ); } } else if ( sscanf( input, "%f %f %f %f %f %f %f %f %f", &coord[0][0], &coord[0][1], &coord[0][2], &coord[1][0], &coord[1][1], &coord[1][2], &coord[2][0], &coord[2][1], &coord[2][2] ) == 9 ) { Poly * p = Poly::get(); printf( "read poly: %d\n", p->id ); for ( int i = 0; i < 3; i++ ) { p->coord[0][i] = coord[0][i]; p->coord[1][i] = coord[1][i]; p->coord[2][i] = coord[2][i]; } p->calculateNormal(); tree.addPoly( p ); } } return 0; } #endif // 0 mm3d-master/src/libmm3d/bsptree.h000066400000000000000000000062251324021725400171470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BSPTREE_H #define __BSPTREE_H #include "drawcontext.h" #include class BspTree { public: class Poly { public: static Poly * get(); void release(); static int flush(); static void stats(); int id; float coord[3][3]; float drawNormals[3][3]; int texture; void * material; // Yeah, yeah, I know... it's hackish void * triangle; // Yeah, yeah, I know... it's hackish float s[3]; // texture coordinates float t[3]; float norm[3]; float d; // dot product void calculateNormal(); void calculateD(); void intersection( float * p1, float * p2, float * po, float & place ); void render( DrawingContext * context ); void print(); protected: Poly() : id( ++s_nextId ) { s_allocated++; }; virtual ~Poly() { s_allocated--; }; static int s_nextId; static std::list< Poly * > s_recycle; static int s_allocated; }; class Node { public: static Node * get(); void release(); static int flush(); static void stats(); void addChild( Node * n ); void render( float * point, DrawingContext * context ); void splitNodes( int idx1, int idx2, int idx3, float * p1, float * p2, Node * n1, Node * n2, const float & place1, const float & place2 ); void splitNode( int idx1, int idx2, int idx3, float * p1, Node * n1, const float & place ); Poly * self; Node * left; Node * right; protected: Node() : self( NULL ), left( NULL ), right( NULL ) { s_allocated++;}; virtual ~Node() { s_allocated--; }; static std::list< Node * > s_recycle; static int s_allocated; }; BspTree() : m_root( NULL ) {}; virtual ~BspTree() { clear(); }; void addPoly( Poly * p ); void render( float * point, DrawingContext * context ); void clear(); protected: Node * m_root; }; #endif // __BSPTREE_H mm3d-master/src/libmm3d/cal3dfilter.cc000066400000000000000000002215531324021725400200400ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // Cal 3D notes: // // Main file may be .cal or .cfg // // The .cal file may be ascii text .ini style, or XML. The XML .cal file // format is not supported. // // Versions: // // Version numbers are decimal // // Binary version 700 = XML Version 900 or 1000 // // XML version 900: // File has a
element with version // XML version 1000: // No header, version is part of top-level tag // // Binary version 1200: // Animation has an extra flag field at the start that indicates if // the animation tracks are compressed, plus possibly compressed tracks. // FIXME things to test: // // Read compressed tracks (TEST) // Are .cal and .cfg different? Looks like mesh/animation keys // don't have names (mesh= instead of mesh_foo=) #include "cal3dfilter.h" #include "model.h" #include "texture.h" #include "log.h" #include "endianconfig.h" #include "misc.h" #include "filtermgr.h" #include "texmgr.h" #include "mesh.h" #include "modelstatus.h" #include "mm3dport.h" #include "translate.h" #include "datadest.h" #include "datasource.h" #include "file_closer.h" #include "local_array.h" #include "release_ptr.h" #include #include #include #include #include #include #include using std::list; using std::string; #ifdef PLUGIN static Cal3dFilter * s_filter = NULL; #endif // PLUGIN // These values are decimal, not hexadecimal #define CAL3D_MIN_BVERSION 700 #define CAL3D_MAX_BVERSION 1200 #define CAL3D_MIN_XVERSION 900 #define CAL3D_MAX_XVERSION 1000 // Versions where formats changed. Files with versions equal to or later than // these may make use of newer features. #define CAL3D_COMP_ANIM_VERSION 1200 // Compressed animation tracks #define CAL3D_NO_XHEADER_VERSION 1000 // XML files without
tags (version goes in top-level tag) // File magic number values #define CAL3D_MAGIC_SIZE 4 #define CAL3D_MAGIC_MATERIAL "CRF\0" #define CAL3D_MAGIC_MESH "CMF\0" #define CAL3D_MAGIC_SKELETON "CSF\0" #define CAL3D_MAGIC_ANIMATION "CAF\0" const Model::AnimationModeE MODE = Model::ANIMMODE_SKELETAL; static char * _skipSpace( char * str ) { while ( isspace( str[0] ) ) { str++; } return str; } static bool isallowed( char ch ) { switch ( ch ) { case '_': case '-': case '.': case '+': return true; default: break; } return false; } static void _escapeCal3dName( std::string & name ) { size_t i = 0; while ( i < name.size() ) { if ( isspace( name[i] ) ) { name[i] = '_'; i++; } else if ( !isalnum( name[i] ) && !isallowed( name[i] ) ) { name.erase(i,1); } else { i++; } } } static void _escapeFileName( std::string & file ) { _escapeCal3dName( file ); // for now this is the same code } static void _strtolower( std::string & str ) { size_t i = 0; for ( i = 0; i < str.size(); i++ ) { str[i] = tolower( str[i] ); } } Cal3dFilter::Cal3dOptions::Cal3dOptions() : m_singleMeshFile( true ), m_xmlMatFile( true ) { } Cal3dFilter::Cal3dOptions::~Cal3dOptions() { } void Cal3dFilter::Cal3dOptions::setOptionsFromModel( Model * m ) { char value[32]; if ( m->getMetaData( "cal3d_single_mesh_file", value, sizeof(value) ) ) { // Non-zero, single mesh m_singleMeshFile = atoi(value) != 0; } if ( m->getMetaData( "cal3d_xml_material", value, sizeof(value) ) ) { // Non-zero, use XML format for material m_xmlMatFile = atoi(value) != 0; } } Cal3dFilter::Cal3dFilter() : m_model( NULL ), m_options( NULL ) { m_formats.push_back( "cal" ); m_formats.push_back( "cfg" ); } Cal3dFilter::~Cal3dFilter() { } Model::ModelErrorE Cal3dFilter::readFile( Model * model, const char * const filename ) { Model::ModelErrorE err = Model::ERROR_NONE; // Use these to determine what versions of files to write. m_maxBinaryVersion = CAL3D_MIN_BVERSION; m_maxXrfVersion = CAL3D_MIN_XVERSION; if ( (err = readFileToBuffer( filename, m_fileBuf, m_fileLength )) == Model::ERROR_NONE ) { local_array releaseBuf( m_fileBuf ); m_bufPos = m_fileBuf; m_modelPath = ""; m_modelBaseName = ""; m_modelFullName = ""; normalizePath( filename, m_modelFullName, m_modelPath, m_modelBaseName ); m_currentPath = m_modelPath; model->setFilename( m_modelFullName.c_str() ); m_model = model; // Read specified file based on magic if ( memcmp( m_fileBuf, CAL3D_MAGIC_SKELETON, CAL3D_MAGIC_SIZE ) == 0 ) { err = readSkeletonFile( m_fileBuf, m_fileLength ); } else if ( memcmp( m_fileBuf, CAL3D_MAGIC_ANIMATION, CAL3D_MAGIC_SIZE ) == 0 ) { err = readAnimationFile( m_fileBuf, m_fileLength ); } else if ( memcmp( m_fileBuf, CAL3D_MAGIC_MESH, CAL3D_MAGIC_SIZE ) == 0 ) { m_model->updateMetaData( "cal3d_single_mesh_file", "1" ); err = readMeshFile( m_fileBuf, m_fileLength ); } else if ( memcmp( m_fileBuf, CAL3D_MAGIC_MATERIAL, CAL3D_MAGIC_SIZE ) == 0 ) { err = readMaterialFile( m_fileBuf, m_fileLength ); } else if ( m_fileBuf[0] == '<' ) { // probably an XML file, we only support material files err = readXSubFile( m_fileBuf, m_fileLength ); } else { err = readCal3dFile( m_fileBuf, m_fileLength ); } m_model->setupJoints(); log_debug( "Cal3D Model:\n" ); log_debug( " vertices: %d\n", m_model->getVertexCount() ); log_debug( " faces: %d\n", m_model->getTriangleCount() ); log_debug( " groups: %d\n", m_model->getGroupCount() ); log_debug( " bones: %d\n", m_model->getBoneJointCount() ); log_debug( " materials: %d\n", m_model->getTextureCount() ); m_fileBuf = NULL; m_bufPos = NULL; } char version[32]; PORT_snprintf( version, sizeof(version), "%d", m_maxXrfVersion ); model->updateMetaData( "cal3d_xrf_version", version ); PORT_snprintf( version, sizeof(version), "%d", m_maxBinaryVersion ); model->updateMetaData( "cal3d_binary_version", version ); return err; } Model::ModelErrorE Cal3dFilter::writeFile( Model * model, const char * const filename, ModelFilter::Options * o ) { if ( filename == NULL || filename[0] == '\0' ) { return Model::ERROR_BAD_ARGUMENT; } m_modelPath = ""; m_modelBaseName = ""; m_modelFullName = ""; normalizePath( filename, m_modelFullName, m_modelPath, m_modelBaseName ); m_model = model; m_options = NULL; const char * ext = strrchr( filename, '.' ); if ( ext ) { ext++; if ( strcasecmp( ext, "CSF" ) == 0 ) { return writeSkeletonFile( filename, model ); } else if ( strcasecmp( ext, "CAF" ) == 0 ) { if ( model->getAnimCount( MODE ) > 0 ) { return writeAnimationFile( filename, model, 0 ); } return Model::ERROR_BAD_DATA; } else if ( strcasecmp( ext, "CMF" ) == 0 ) { return writeMeshFile( filename, model ); } else if ( strcasecmp( ext, "CRF" ) == 0 ) { if ( model->getTextureCount() > 0 ) { return writeMaterialFile( filename, model, 0 ); } return Model::ERROR_BAD_DATA; } else if ( strcasecmp( ext, "XRF" ) == 0 ) { if ( model->getTextureCount() > 0 ) { return writeXMaterialFile( filename, model, 0 ); } return Model::ERROR_BAD_DATA; } else if ( toupper(ext[0]) == 'X' ) { // Assume XML file return Model::ERROR_UNSUPPORTED_VERSION; } // Assume Cal3D master file return writeCal3dFile( filename, model, o ); } else { return writeCal3dFile( filename, model, o ); } } bool Cal3dFilter::canRead( const char * filename ) { log_debug( "canRead( %s )\n", filename ); log_debug( " true\n" ); return true; } bool Cal3dFilter::canWrite( const char * filename ) { log_debug( "canWrite( %s )\n", filename ); log_debug( " false\n" ); return false; } bool Cal3dFilter::canExport( const char * filename ) { log_debug( "canExport( %s )\n", filename ); log_debug( " true\n" ); return true; } bool Cal3dFilter::isSupported( const char * filename ) { log_debug( "isSupported( %s )\n", filename ); unsigned len = strlen(filename); for ( std::list::const_iterator it = m_formats.begin(); it != m_formats.end(); ++it ) { const std::string fmt = std::string(".") + *it; unsigned fmtlen = fmt.size(); if ( len >= fmtlen && strcasecmp( &filename[len-fmtlen], fmt.c_str() ) == 0 ) { log_debug( " true\n" ); return true; } } log_debug( " false\n" ); return false; } list< string > Cal3dFilter::getReadTypes() { list rval; for ( std::list::const_iterator it = m_formats.begin(); it != m_formats.end(); ++it ) { rval.push_back( std::string("*.") + *it ); } return rval; } list< string > Cal3dFilter::getWriteTypes() { list rval; for ( std::list::const_iterator it = m_formats.begin(); it != m_formats.end(); ++it ) { rval.push_back( std::string("*.") + *it ); } return rval; } //------------------------------------------------------------------ // Protected Methods //------------------------------------------------------------------ bool Cal3dFilter::listHas( const std::list & l, const std::string & val ) { std::list::const_iterator it = l.begin(); while ( it != l.end() ) { if ( (*it) == val ) { return true; } it++; } return false; } std::string Cal3dFilter::addExtension( const std::string file, const std::string ext ) { if ( file.size() > ext.size() ) { std::string cmp = std::string(".") + ext; size_t len = cmp.size() - file.size(); if ( strcasecmp( &(file.c_str()[file.size() - len]), ext.c_str() ) == 0 ) { return file; } } return file + std::string(".") + ext; } bool Cal3dFilter::versionIsValid( FileTypeE type, int version ) { if ( version >= CAL3D_MIN_BVERSION && version <= CAL3D_MAX_BVERSION ) { return true; } return false; } bool Cal3dFilter::xversionIsValid( FileTypeE type, int version ) { if ( version >= CAL3D_MIN_XVERSION && version <= CAL3D_MAX_XVERSION ) { return true; } return false; } //------------------------------------------------------------------ // Common read functions Model::ModelErrorE Cal3dFilter::readSubFile( const char * filename ) { Model::ModelErrorE err = Model::ERROR_NONE; std::string oldPath = m_currentPath; std::string fullPath = m_currentPath + std::string( "/" ) + filename; uint8_t * buf; size_t len; if ( (err = readFileToBuffer( fullPath.c_str(), buf, len )) == Model::ERROR_NONE ) { local_array releaseBuf(buf); std::string baseName; std::string fullName; normalizePath( fullPath.c_str(), fullName, m_currentPath, baseName ); const char * part = strrchr( filename, '/' ); if ( part ) { part++; } else { part = filename; } const char * ext = strrchr( filename, '.' ); if ( ext ) { m_modelPartName.assign( part, ext - part ); m_modelPartExt = &ext[1]; } else { m_modelPartName = part; } // Read specified file based on magic if ( memcmp( buf, CAL3D_MAGIC_SKELETON, CAL3D_MAGIC_SIZE ) == 0 ) { err = readSkeletonFile( buf, len ); } else if ( memcmp( buf, CAL3D_MAGIC_ANIMATION, CAL3D_MAGIC_SIZE ) == 0 ) { err = readAnimationFile( buf, len ); } else if ( memcmp( buf, CAL3D_MAGIC_MESH, CAL3D_MAGIC_SIZE ) == 0 ) { err = readMeshFile( buf, len ); } else if ( memcmp( buf, CAL3D_MAGIC_MATERIAL, CAL3D_MAGIC_SIZE ) == 0 ) { err = readMaterialFile( buf, len ); } else if ( buf[0] == '<' ) { // probably an XML file, try to parse it err = readXSubFile( buf, len ); } else { err = readCal3dFile( buf, len ); } m_currentPath = oldPath; } if ( err != Model::ERROR_NONE ) { std::string errStr = filename; errStr += ": "; errStr += Model::errorToString( err ); model_status( m_model, StatusError, STATUSTIME_LONG, errStr.c_str() ); } return err; } Model::ModelErrorE Cal3dFilter::readXSubFile( uint8_t * buf, size_t len ) { Model::ModelErrorE err = Model::ERROR_UNSUPPORTED_VERSION; uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; // Only support material XML files // Some versions of CAL3D files have a header element, some do not // If we see a HEADER element, get the MAGIC attribute if ( findXElement( "HEADER" ) ) { log_debug( "XML file has a
element\n" ); std::string magic = readXAttribute( "MAGIC" ); if ( strcmp( magic.c_str(), "XRF" ) == 0 ) { log_debug( "XML file is a material file\n" ); err = readXMaterialFile( buf, len ); } else { log_warning( "XML file is an unknown type: %s\n", magic.c_str() ); } } else if ( findXElement( "MATERIAL" ) ) { log_debug( "XML file does not have a header\n" ); log_debug( "XML file is a material file\n" ); err = readXMaterialFile( buf, len ); } else { log_debug( "Could not determine XML file type\n" ); log_warning( "XML file is an unsupported type (unrecognized root tag)\n" ); } m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return err; } Model::ModelErrorE Cal3dFilter::readCal3dFile( uint8_t * buf, size_t len ) { log_debug( "reading cal3d config file\n" ); Model::ModelErrorE rval = Model::ERROR_NONE; uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; string line = ""; string subfile = ""; // We start in the [model] section. Technically this is // incorrect, but it's an attempt to get around possible // bad files or bad parsing logic. This shouldn't hurt anything. // If there is a non-model section before the model section // it will be skipped. bool modelSection = true; // Save mesh, material, and animation files so we can // load them in our own preferred order. The only thing // we load as soon as we see it is the skeleton file. std::list< std::string > meshFiles; std::list< std::string > matFiles; std::list< std::string > animFiles; // If no usable data is found, the bracket count (ie, number of lines // that start with '<') is used to determine if the file was in XML format // so that we can give a more useful error message to the user. int bracketCount = 0; bool noData = true; while ( readBLine( line, len - (m_bufPos - m_fileBuf) ) ) { if ( modelSection ) { const char * str = _skipSpace( (char *) line.c_str() ); // only parse lines that are not empty or comments if ( str[0] && str[0] != '#' ) { if ( strncasecmp( str, "skeleton", 8 ) == 0 ) { noData = false; subfile = readLineFile( str ); if ( !subfile.empty() ) { log_debug( "loading skeleton file %s\n", subfile.c_str() ); readSubFile( subfile.c_str() ); } } else if ( strncasecmp( str, "mesh", 4 ) == 0 ) { noData = false; subfile = readLineFile( str ); if ( !subfile.empty() ) { meshFiles.push_back( subfile ); } } else if ( strncasecmp( str, "animation", 9 ) == 0 ) { noData = false; std::string animLabel = readLineKey( str ); subfile = readLineFile( str ); if ( !subfile.empty() && !animLabel.empty() ) { m_model->updateMetaData( animLabel.c_str(), subfile.c_str() ); if ( !listHas( animFiles, subfile ) ) { animFiles.push_back( subfile ); } } } else if ( strncasecmp( str, "material", 8 ) == 0 ) { noData = false; subfile = readLineFile( str ); if ( !subfile.empty() ) { matFiles.push_back( subfile ); } } else if ( strncasecmp( str, "path", 4 ) == 0 ) { noData = false; string value = readLineFile( str ); m_model->updateMetaData( "cal3d_path", value.c_str() ); } else if ( strncasecmp( str, "scale", 5 ) == 0 ) { noData = false; string value = readLineFile( str ); m_model->updateMetaData( "cal3d_scale", value.c_str() ); } else if ( strncasecmp( str, "rotate", 6 ) == 0 ) { noData = false; string value = readLineFile( str ); m_model->updateMetaData( "cal3d_rotate", value.c_str() ); } else if ( str[0] == '[' ) { // looks like a new section, see if it's a model section str++; while ( isspace( str[0] ) ) { str++; } if ( strncasecmp( str, "model", 5 ) == 0 ) { modelSection = true; } else { // Not a model section, skip it log_debug( "skipping [%s section\n", str ); modelSection = false; } } else if ( str[0] == '<' ) { ++bracketCount; } } if ( (m_bufPos - m_fileBuf) >= (int) m_fileLength ) { break; } } else { // Not in the model section, the only parsing we want // to do is to find the model section... const char * str = _skipSpace( (char *) line.c_str() ); if ( str[0] == '[' ) { // looks like a new section, see if it's a model section str++; while ( isspace( str[0] ) ) { str++; } if ( strncasecmp( str, "model", 5 ) == 0 ) { // Yes, it's a model section, enable the parsing logic log_debug( "entering model section\n" ); modelSection = true; } else { log_debug( "skipping [%s section\n", str ); modelSection = false; } } if ( (m_bufPos - m_fileBuf) >= (int) m_fileLength ) { break; } } } std::list< std::string >::iterator it; // If we didn't find any usable data, return an error. if ( noData ) { if ( bracketCount > 2 ) m_model->setFilterSpecificError( transll( QT_TRANSLATE_NOOP( "LowLevel", "MM3D does not support CAL3D files in XML format" ) ).c_str() ); else m_model->setFilterSpecificError( transll( QT_TRANSLATE_NOOP( "LowLevel", "The file does not contain any mesh or animation data" ) ).c_str() ); rval = Model::ERROR_FILTER_SPECIFIC; goto bail_out; } // Load materials first because meshes will reference them for ( it = matFiles.begin(); it != matFiles.end(); it++ ) { log_debug( "loading material file %s\n", (*it).c_str() ); readSubFile( (*it).c_str() ); } // Now load meshes for ( it = meshFiles.begin(); it != meshFiles.end(); it++ ) { log_debug( "loading mesh file %s\n", (*it).c_str() ); readSubFile( (*it).c_str() ); } m_model->updateMetaData( "cal3d_single_mesh_file", ( meshFiles.size() == 1 ) ? "1" : "0" ); // Now load animations for ( it = animFiles.begin(); it != animFiles.end(); it++ ) { log_debug( "loading animation file %s\n", (*it).c_str() ); readSubFile( (*it).c_str() ); } bail_out:; m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readSkeletonFile( uint8_t * buf, size_t len ) { uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; Model::ModelErrorE rval = Model::ERROR_NONE; if ( memcmp( CAL3D_MAGIC_SKELETON, m_bufPos, CAL3D_MAGIC_SIZE ) == 0 ) { m_bufPos += CAL3D_MAGIC_SIZE; int fileVersion = readBInt32(); int numBones = readBInt32(); if ( fileVersion > m_maxBinaryVersion ) m_maxBinaryVersion = fileVersion; log_debug( "skel version: %d (%x)\n", fileVersion, fileVersion ); bool success = true; if ( versionIsValid( FT_Skeleton, fileVersion ) ) { for ( int b = 0; success && b < numBones; b++ ) { success = readBBone(); } } else { rval = Model::ERROR_UNSUPPORTED_VERSION; log_error( "Unsupported CAL3D skeleton version %d\n", fileVersion ); } } else { rval = Model::ERROR_BAD_MAGIC; log_error( "Bad magic in skeleton file\n" ); } m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readMeshFile( uint8_t * buf, size_t len ) { uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; Model::ModelErrorE rval = Model::ERROR_NONE; if ( memcmp( CAL3D_MAGIC_MESH, m_bufPos, CAL3D_MAGIC_SIZE ) == 0 ) { m_bufPos += CAL3D_MAGIC_SIZE; int fileVersion = readBInt32(); int numSubMeshes = readBInt32(); if ( fileVersion > m_maxBinaryVersion ) m_maxBinaryVersion = fileVersion; log_debug( "mesh version: %d (%x)\n", fileVersion, fileVersion ); bool success = true; if ( versionIsValid( FT_Mesh, fileVersion ) ) { for ( int m = 0; success && m < numSubMeshes; m++ ) { success = readBSubMesh(); } } else { rval = Model::ERROR_UNSUPPORTED_VERSION; log_error( "Unsupported CAL3D mesh version %d\n", fileVersion ); } } else { rval = Model::ERROR_BAD_MAGIC; log_error( "Bad magic in mesh file\n" ); } m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readMaterialFile( uint8_t * buf, size_t len ) { uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; m_model->updateMetaData( "cal3d_xml_material", "0" ); Model::ModelErrorE rval = Model::ERROR_NONE; // We're going to add a material whether successful or not. Materials are // referenced by index so the material needs to exist even if it's not valid. Model::Material * mat = Model::Material::get(); mat->m_type = Model::Material::MATTYPE_BLANK; // assume mat->m_name = m_modelPartName; // this should be a sensible name mat->m_filename = ""; // none by default if ( memcmp( CAL3D_MAGIC_MATERIAL, m_bufPos, CAL3D_MAGIC_SIZE ) == 0 ) { m_bufPos += CAL3D_MAGIC_SIZE; int fileVersion = readBInt32(); if ( fileVersion > m_maxBinaryVersion ) m_maxBinaryVersion = fileVersion; log_debug( "mat version: %d (%x)\n", fileVersion, fileVersion ); if ( versionIsValid( FT_Material, fileVersion ) ) { Vector ambient; ambient[0] = ((float) readBUInt8()) / 255.0f; ambient[1] = ((float) readBUInt8()) / 255.0f; ambient[2] = ((float) readBUInt8()) / 255.0f; ambient[3] = ((float) readBUInt8()) / 255.0f; Vector diffuse; diffuse[0] = ((float) readBUInt8()) / 255.0f; diffuse[1] = ((float) readBUInt8()) / 255.0f; diffuse[2] = ((float) readBUInt8()) / 255.0f; diffuse[3] = ((float) readBUInt8()) / 255.0f; Vector specular; specular[0] = ((float) readBUInt8()) / 255.0f; specular[1] = ((float) readBUInt8()) / 255.0f; specular[2] = ((float) readBUInt8()) / 255.0f; specular[3] = ((float) readBUInt8()) / 255.0f; float shiny = readBFloat(); int numMaps = readBInt32(); if ( numMaps > 0 ) { // Texture-map, change type and add filename string filename; readBString( filename ); mat->m_type = Model::Material::MATTYPE_TEXTURE; mat->m_filename = normalizePath(filename.c_str(), m_currentPath.c_str()); // ignore everything else in the file } log_debug( "Reading material %d\n", m_model->getTextureCount() ); log_debug( " name %s\n", mat->m_name.c_str() ); log_debug( " num maps %d\n", numMaps ); log_debug( " file %s\n", mat->m_filename.c_str() ); log_debug( " diffuse %f,%f,%f\n", diffuse[0], diffuse[1], diffuse[2] ); log_debug( " ambient %f,%f,%f\n", ambient[0], ambient[1], ambient[2] ); log_debug( " specular %f,%f,%f\n", specular[0], specular[1], specular[2] ); log_debug( " shininess %f\n", shiny ); if ( numMaps > 1 ) { log_warning( " ignoring %d maps for %s\n", numMaps - 1, mat->m_name.c_str() ); } for ( int t = 0; t < 4; t++ ) { mat->m_diffuse[t] = diffuse[t]; mat->m_ambient[t] = ambient[t]; mat->m_specular[t] = specular[t]; mat->m_emissive[t] = 0.0f; } mat->m_shininess = shiny; } else { rval = Model::ERROR_UNSUPPORTED_VERSION; log_error( "Unsupported CAL3D material version %d\n", fileVersion ); } } else { rval = Model::ERROR_BAD_MAGIC; log_error( "Bad magic in material file\n" ); } getMaterialList( m_model ).push_back( mat ); m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readXMaterialFile( uint8_t * buf, size_t len ) { uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; m_model->updateMetaData( "cal3d_xml_material", "1" ); Model::ModelErrorE rval = Model::ERROR_NONE; // We're going to add a material whether successful or not. Materials are // referenced by index so the material needs to exist even if it's not valid. Model::Material * mat = Model::Material::get(); mat->m_type = Model::Material::MATTYPE_BLANK; // assume mat->m_name = m_modelPartName; // this should be a sensible name mat->m_filename = ""; // none by default if ( len > 0 ) { // don't worry about magic and version, just get to the material tag if ( findXElement( "MATERIAL" ) ) { std::string versionStr = readXAttribute( "VERSION" ); int xrfVersion = atoi( versionStr.c_str() ); if ( xrfVersion > m_maxXrfVersion ) m_maxXrfVersion = xrfVersion; Vector ambient( 0, 0, 0, 1 ); Vector diffuse( 1, 1, 1, 1 ); Vector specular( 0, 0, 0, 1 ); string matFile = ""; float shiny = 0.0f; if ( findXElement( "AMBIENT" ) ) { ambient = readAVector4( readXElement( "AMBIENT" ).c_str() ); ambient[0] /= 255.0; ambient[1] /= 255.0; ambient[2] /= 255.0; ambient[3] /= 255.0; } if ( findXElement( "DIFFUSE" ) ) { diffuse = readAVector4( readXElement( "DIFFUSE" ).c_str() ); diffuse[0] /= 255.0; diffuse[1] /= 255.0; diffuse[2] /= 255.0; diffuse[3] /= 255.0; } if ( findXElement( "SPECULAR" ) ) { specular = readAVector4( readXElement( "SPECULAR" ).c_str() ); specular[0] /= 255.0; specular[1] /= 255.0; specular[2] /= 255.0; specular[3] /= 255.0; } if ( findXElement( "SHININESS" ) ) { shiny = atof( readXElement( "SHININESS" ).c_str() ); } if ( findXElement( "MAP" ) ) { matFile = readAString( readXElement( "MAP" ).c_str() ); } if ( !matFile.empty() ) { mat->m_type = Model::Material::MATTYPE_TEXTURE; mat->m_filename = normalizePath(matFile.c_str(), m_currentPath.c_str()); } log_debug( "Reading material %d\n", m_model->getTextureCount() ); log_debug( " name %s\n", mat->m_name.c_str() ); log_debug( " file %s\n", mat->m_filename.c_str() ); log_debug( " diffuse %f,%f,%f\n", diffuse[0], diffuse[1], diffuse[2] ); log_debug( " ambient %f,%f,%f\n", ambient[0], ambient[1], ambient[2] ); log_debug( " specular %f,%f,%f\n", specular[0], specular[1], specular[2] ); log_debug( " shininess %f\n", shiny ); for ( int t = 0; t < 4; t++ ) { mat->m_diffuse[t] = diffuse[t]; mat->m_ambient[t] = ambient[t]; mat->m_specular[t] = specular[t]; mat->m_emissive[t] = 0.0f; } mat->m_shininess = shiny; } else { rval = Model::ERROR_BAD_MAGIC; log_error( "Could not find MATERIAL element in material file\n" ); } } else { rval = Model::ERROR_FILE_READ; log_error( "File is empty\n" ); } getMaterialList( m_model ).push_back( mat ); m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readAnimationFile( uint8_t * buf, size_t len ) { uint8_t * oldFileBuf = m_fileBuf; uint8_t * oldBufPos = m_bufPos; size_t oldLen = m_fileLength; m_fileBuf = buf; m_bufPos = buf; m_fileLength = len; Model::ModelErrorE rval = Model::ERROR_NONE; if ( memcmp( CAL3D_MAGIC_ANIMATION, m_bufPos, CAL3D_MAGIC_SIZE ) == 0 ) { m_bufPos += CAL3D_MAGIC_SIZE; int fileVersion = readBInt32(); float duration = readBFloat(); int numTracks = readBInt32(); if ( fileVersion > m_maxBinaryVersion ) m_maxBinaryVersion = fileVersion; log_debug( "anim version: %d (%x)\n", fileVersion, fileVersion ); if ( versionIsValid( FT_Animation, fileVersion ) ) { std::string name = m_modelPartName; bool compressed = false; if ( fileVersion >= CAL3D_COMP_ANIM_VERSION ) { int flags = readBInt32(); compressed = ( (flags & 1) != 0 ); } //name += "."; //name += m_modelPartExt; //log_debug( " tracks: %d\n", numTracks ); //log_debug( " seconds: %f\n", duration ); // create animation // NOTE: assume 30 fps, may want to be smarter about this m_anim = m_model->addAnimation( MODE, name.c_str() ); m_model->setAnimFPS( MODE, m_anim, 30.0 ); m_model->setAnimFrameCount( MODE, m_anim, timeToFrame(duration, 30.0) + 1); bool success = true; for ( int t = 0; success && t < numTracks; t++ ) { if ( compressed ) success = readBCompressedAnimTrack( duration ); else success = readBAnimTrack(); } } else { rval = Model::ERROR_UNSUPPORTED_VERSION; log_error( "Unsupported CAL3D animation version %d\n", fileVersion ); } } else { rval = Model::ERROR_BAD_MAGIC; log_error( "Bad magic in mesh file\n" ); } m_fileBuf = oldFileBuf; m_bufPos = oldBufPos; m_fileLength = oldLen; return rval; } Model::ModelErrorE Cal3dFilter::readFileToBuffer( const char * filename, uint8_t * & buf, size_t & len ) { buf = NULL; len = 0; Model::ModelErrorE err = Model::ERROR_NONE; DataSource * src = openInput( filename, err ); SourceCloser fc( src ); if ( err != Model::ERROR_NONE ) return err; len = src->getFileSize(); buf = new uint8_t[len]; src->readBytes( buf, len ); return err; } bool Cal3dFilter::readBBone() { log_debug( "Reading bone joint %d\n", m_model->getBoneJointCount() ); // Bone name std::string name; readBString( name ); log_debug( " name %s\n", name.c_str() ); // Bone position Vector trans = readBVector3(); Vector rotVec = readBVector4(); // Bone space translation Vector transLocal = readBVector3(); Vector rotQuatLocal = readBVector4(); log_debug( " pos = %.4f,%.4f,%.4f\n", trans[0], trans[1], trans[2] ); log_debug( " rot = %.4f,%.4f,%.4f,%.4f\n", rotVec[0], rotVec[1], rotVec[2], rotVec[3] ); log_debug( " lpos = %.4f,%.4f,%.4f\n", transLocal[0], transLocal[1], transLocal[2] ); log_debug( " lrot = %.4f,%.4f,%.4f,%.4f\n", rotQuatLocal[0], rotQuatLocal[1], rotQuatLocal[2], rotQuatLocal[3] ); // Parent bone joint int parent = readBInt32(); log_debug( " parent %d\n", parent ); // Children... we don't need this data, just skip past it int childCount = readBInt32(); //log_debug( " children %d\n", childCount ); for ( int c = 0; c < childCount; c++ ) { readBInt32(); } Quaternion rotQuat( rotVec ); Vector rot; // left-handed to right-handed conversion rotQuat = rotQuat.swapHandedness(); Matrix bmat; bmat.setRotationQuaternion( rotQuat ); bmat.setTranslation( trans ); // NOTE: This will not work if we're adding a joint with a parent // that is defined after us if ( parent >= 0 ) { if ( parent < m_model->getBoneJointCount() ) { Matrix pmat; m_model->getBoneJointAbsoluteMatrix( parent, pmat ); bmat = bmat * pmat; } else { log_error( " parent %d does not exist (yet)\n", parent ); } } //log_debug( " pre trans %f,%f,%f\n", // (float) trans[0], (float) trans[1], (float) trans[2] ); bmat.getTranslation( trans ); bmat.getRotation( rot ); //log_debug( " post trans %f,%f,%f\n", // (float) trans[0], (float) trans[1], (float) trans[2] ); /* log_debug( " rot %f,%f,%f\n", (float) rot[0], (float) rot[1], (float) rot[2] ); log_debug( " local trans %f,%f,%f\n", (float) transLocal[0], (float) transLocal[1], (float) transLocal[2] ); */ m_model->addBoneJoint( name.c_str(), trans[0], trans[1], trans[2], rot[0], rot[1], rot[2], parent ); return true; } bool Cal3dFilter::readBSubMesh() { log_debug( "Reading sub mesh %d\n", m_model->getGroupCount() ); int vertBase = m_model->getVertexCount(); int matId = readBInt32(); int numVerts = readBInt32(); int numFaces = readBInt32(); int numLOD = readBInt32(); int numSprings = readBInt32(); int numMaps = readBInt32(); string name = m_modelPartName; log_debug( " name: %s\n", name.c_str() ); log_debug( " material: %d\n", matId ); log_debug( " verts: %d\n", numVerts ); log_debug( " faces: %d\n", numFaces ); log_debug( " LOD steps: %d\n", numLOD ); log_debug( " springs: %d\n", numSprings ); log_debug( " maps: %d\n", numMaps ); if ( matId >= m_model->getTextureCount() ) { log_error( " material %d is out of range\n", matId ); } int group = m_model->addGroup( name.c_str() ); m_model->setGroupTextureId( group, matId ); UVList uvlist; // read vertices for ( int v = 0; v < numVerts; v++ ) { Vector pos = readBVector3(); readBVector3(); // normal, ignore it // LOD stuff, we ignore it readBInt32(); // vertex to collapse to readBInt32(); // number of faces collapsed // Add the vertex itself int vert = m_model->addVertex( pos[0], pos[1], pos[2] ); // Read UV for ( int m = 0; m < numMaps; m++ ) { float u = readBFloat(); float v = readBFloat(); // ignore unless it's the first one if ( m == 0 ) { // our vertices are per face, not per vertex // save this for faces section UVDataT uv; uv.u = u; uv.v = v; uvlist.push_back( uv ); } } // Read influences int numBones = readBInt32(); for ( int b = 0; b < numBones; b++ ) { int boneId = readBInt32(); float boneWeight = readBFloat(); if ( boneId < m_model->getBoneJointCount() ) { m_model->addVertexInfluence( vert, boneId, Model::IT_Custom, boneWeight ); } else { log_warning( " bone joint %d for vertex %d is out of range\n", boneId, vert ); } } if ( numSprings ) { // spring weight, only present if springs, ignore it readBFloat(); } } // read (and ignore) springs for ( int s = 0; s < numSprings; s++ ) { readBInt32(); // vertex 1 readBInt32(); // vertex 2 readBFloat(); // spring coefficient readBFloat(); // length of spring at rest (idle) } int vcount = m_model->getVertexCount(); int uvcount = uvlist.size(); // read faces for ( int f = 0; f < numFaces; f++ ) { int v1 = readBInt32(); int v2 = readBInt32(); int v3 = readBInt32(); if ( v1 < vcount && v2 < vcount && v3 < vcount ) { int tri = m_model->addTriangle( v1 + vertBase, v2 + vertBase, v3 + vertBase ); m_model->addTriangleToGroup( group, tri ); if ( v1 < uvcount && v2 < uvcount && v3 < uvcount ) { m_model->setTextureCoords( tri, 0, uvlist[v1].u, uvlist[v1].v ); m_model->setTextureCoords( tri, 1, uvlist[v2].u, uvlist[v2].v ); m_model->setTextureCoords( tri, 2, uvlist[v3].u, uvlist[v3].v ); } else { if ( uvcount > 0 ) { log_warning( "face vertex (%d,%d,%d) not in uvlist %d\n", v1, v2, v3, uvcount ); } } } else { log_error( "a vertex is out of range (%d,%d,%d) > %d\n", v1, v2, v3, vcount ); } } return true; } bool Cal3dFilter::readBAnimTrack() { //log_debug( "Reading animation track\n" ); int bone = readBInt32(); int numFrames = readBInt32(); //log_debug( " bone: %d\n", bone ); //log_debug( " frames: %d\n", numFrames ); for ( int f = 0; f < numFrames; f++ ) { float tsec = readBFloat(); // time in seconds Vector trans = readBVector3(); Vector rotVec = readBVector4(); Quaternion quat( rotVec ); quat = quat.swapHandedness(); Matrix m; m.setRotationQuaternion( quat ); m.setTranslation( trans ); // Cal3D anims are relative to joint parent // MM3D are relative to joint local position, convert Matrix inv; m_model->getBoneJointRelativeMatrix( bone, inv ); inv = inv.getInverse(); m = m * inv; double rot[3] = { 0, 0, 0 }; m.getRotation( rot ); m.getTranslation( trans ); int animFrame = timeToFrame( tsec, 30.0 ); m_model->setSkelAnimKeyframe( m_anim, animFrame, bone, true, rot[0], rot[1], rot[2] ); m_model->setSkelAnimKeyframe( m_anim, animFrame, bone, false, trans[0], trans[1], trans[2] ); } return true; } bool Cal3dFilter::readBCompressedAnimTrack( double duration ) { log_debug( "Reading animation track (compressed)\n" ); int bone = readBInt32(); int numFrames = readBInt32(); double scale[3] = { 1.0, 1.0, 1.0 }; double trans_min[3] = { 0.0, 0.0, 0.0 }; int comp_bits[3] = { 10, 11, 11 }; trans_min[0] = readBFloat(); trans_min[1] = readBFloat(); trans_min[2] = readBFloat(); scale[0] = readBFloat(); scale[1] = readBFloat(); scale[2] = readBFloat(); //log_debug( " bone: %d\n", bone ); //log_debug( " frames: %d\n", numFrames ); for ( int f = 0; f < numFrames; f++ ) { uint16_t qsec = readBInt16(); float tsec = (qsec / 65535.0) * duration; uint32_t trans_comp = readBInt32(); uint64_t rot_comp = readBUInt48(); log_debug( "compressed trans = %X rot = %llX\n", trans_comp, rot_comp ); Vector trans; Vector rotVec; for ( int i = 0; i < 3; ++i ) { trans[i] = ((2 << comp_bits[i]) - 1) & trans_comp; trans_comp = trans_comp >> comp_bits[i]; trans[i] /= (double) ((2 << comp_bits[i]) - 1); trans[i] *= scale[i]; } for ( int i = 0; i < 4; ++i ) { rotVec[i] = ((2 << 12) - 1) & rot_comp; rotVec[i] /= (double) ((2 << 12) - 1); rotVec[i] *= 2.0 - 1.0; } log_debug( "uncompressed quat = %f, %f, %f, %f \n", (float) rotVec[0], (float) rotVec[1], (float) rotVec[2], (float) rotVec[3] ); Quaternion quat( rotVec ); quat = quat.swapHandedness(); Matrix m; m.setRotationQuaternion( quat ); m.setTranslation( trans ); // Cal3D anims are relative to joint parent // MM3D are relative to joint local position, convert Matrix inv; m_model->getBoneJointRelativeMatrix( bone, inv ); inv = inv.getInverse(); m = m * inv; double rot[3] = { 0, 0, 0 }; m.getRotation( rot ); m.getTranslation( trans ); int animFrame = timeToFrame( tsec, 30.0 ); log_debug( "rotation (%f,%f,%f) translation (%f,%f,%f)\n", rot[0], rot[1], rot[2], trans[0], trans[1], trans[2] ); m_model->setSkelAnimKeyframe( m_anim, animFrame, bone, true, rot[0], rot[1], rot[2] ); m_model->setSkelAnimKeyframe( m_anim, animFrame, bone, false, trans[0], trans[1], trans[2] ); } return true; } uint64_t Cal3dFilter::readBUInt48() { uint32_t rval32 = readBInt32(); uint16_t rval16 = readBInt16(); uint64_t rval = ((uint64_t) rval16 << 32) | ((uint64_t) rval32); return rval; } int32_t Cal3dFilter::readBInt32() { int32_t rval = *((int32_t *) m_bufPos); m_bufPos += sizeof( rval ); rval = ltoh_u32( rval ); return rval; } int16_t Cal3dFilter::readBInt16() { int16_t rval = *((int16_t *) m_bufPos); m_bufPos += sizeof( rval ); rval = ltoh_u16( rval ); return rval; } uint8_t Cal3dFilter::readBUInt8() { uint8_t rval = *((uint8_t *) m_bufPos); m_bufPos += sizeof( rval ); return rval; } float Cal3dFilter::readBFloat() { float32_t rval = 0.0f; memcpy( &rval, m_bufPos, sizeof(rval ) ); m_bufPos += sizeof( rval ); rval = ltoh_float( rval ); return rval; } bool Cal3dFilter::readBString( std::string & str ) { size_t len = readBInt32(); size_t advance = len; while (len > 0 && m_bufPos[len-1] == '\0') --len; str.assign( (char *) m_bufPos, len ); //log_debug( "read string '%s' at %p\n", str.c_str(), m_bufPos ); m_bufPos += advance; return true; } bool Cal3dFilter::readBLine( std::string & str, size_t maxLen ) { size_t p = 0; size_t skipBytes = 0; for ( p = 0; p < maxLen; p++ ) { if ( m_bufPos[p] == '\n' ) { skipBytes = 1; break; } if ( m_bufPos[p] == '\r' && m_bufPos[p+1] == '\n' ) { skipBytes = 2; break; } } str.assign( (char *) m_bufPos, p ); m_bufPos += p + skipBytes; //log_debug( "size: %d, pos %d\n", maxLen, m_bufPos - m_fileBuf ); if ( (p + skipBytes) > 0 ) { return true; } else { return false; } } Vector Cal3dFilter::readBVector3() { Vector rval; rval[0] = readBFloat(); rval[1] = readBFloat(); rval[2] = readBFloat(); return rval; } Vector Cal3dFilter::readBVector4() { Vector rval; rval[0] = readBFloat(); rval[1] = readBFloat(); rval[2] = readBFloat(); rval[3] = readBFloat(); return rval; } Vector Cal3dFilter::readAVector3( const char * str ) { float fval[3]; sscanf( str, "%f %f %f", &fval[0], &fval[1], &fval[2] ); Vector rval; rval[0] = fval[0]; rval[1] = fval[1]; rval[2] = fval[2]; return rval; } Vector Cal3dFilter::readAVector4( const char * str ) { float fval[4]; sscanf( str, "%f %f %f %f", &fval[0], &fval[1], &fval[2], &fval[3] ); Vector rval; rval[0] = fval[0]; rval[1] = fval[1]; rval[2] = fval[2]; rval[3] = fval[3]; return rval; } std::string Cal3dFilter::readAString( const char * str ) { while ( isspace( str[0] ) ) { str++; } int len = strlen( str ) - 1; while ( len >= 0 && isspace( str[len] ) ) { len--; } len++; std::string rval; rval.assign( str, len ); return rval; } std::string Cal3dFilter::readLineFile( const char * str ) { const char * eq = strchr( str, '=' ); if ( eq ) { const char * start = strchr( eq, '"' ); if ( start ) { start += 1; const char * end = strchr( start, '"' ); if ( end ) { std::string rval; rval.assign( start, end - start ); return rval; } } else { // No quotes... uh... do... something eq++; // skip '=' while ( isspace( eq[0] ) ) { eq++; } return eq; } } return ""; } std::string Cal3dFilter::readLineKey( const char * str ) { const char * eq = strchr( str, '=' ); if ( eq ) { eq--; while (eq > str && isspace(*eq)) { eq--; } std::string rval; rval.assign( str, eq - str + 1 ); return rval; } return ""; } //------------------------------------------------------------------ // XML read functions // XXX: It is important to note that this XML reading functionality is // extremely limited. It is just barely good enough to read Cal3D // XML formats, and is not appropriate for any other uses. // // Why did I write my own instead of using a library? Primarily because // I don't want to increase external dependencies (mostly for portability // reasons). // // Why not use Qt's XML reading since MM3D is already using Qt? Because // the core MM3D model functionality is used in other projects that // do not link against Qt. // // So I wrote 3 XML parsing functions that are extremely limited use, // but "good enough" for what I need. // // Some things that are broken: // - No validity checks on input // - Can't ensure that an element is a sub-element (just looks at the // tags, not the document hierarchy) // - Attribute names must not be substrings of other attribute names // or attribute values in the same element (if there is you could // get a false attribute lookup) // - Text in an attribute value that looks like an element will be // parsed as an element // - It doesn't handle comments (elements in comments will be parsed) bool Cal3dFilter::findXElement( const char * tag ) { const char * buf = (const char *) m_fileBuf; size_t pos = m_bufPos - m_fileBuf; size_t tagLen = strlen( tag ); while ( pos < m_fileLength ) { if ( m_fileBuf[pos] == '<' ) { if ( strncasecmp( &buf[pos+1], tag, tagLen ) == 0) { m_bufPos = &m_fileBuf[pos]; //log_debug( "found tag %s at %p\n", tag, m_bufPos ); return true; } } pos++; } return false; } std::string Cal3dFilter::readXAttribute( const char * attr ) { const char * buf = (const char *) m_fileBuf; size_t pos = m_bufPos - m_fileBuf; size_t attrLen = strlen( attr ); size_t start = 0; bool inAttr = false; while ( pos < m_fileLength - 1 ) { if ( inAttr ) { if ( buf[pos] == '"' ) { std::string rval; rval.assign( &buf[ start ], pos - start ); //log_debug( "attribute: %s = %s\n", attr, rval.c_str() ); return rval; } } else { if ( strncmp( &buf[pos], attr, attrLen ) == 0 ) { pos += attrLen; while ( !inAttr && pos < m_fileLength - 1 ) { // NOTE: This assumes that no attribute name occures // as a sub-string of another attribute name or value. // It also assumes the '=' is present if ( buf[pos] == '"' ) { start = pos + 1; inAttr = true; // pos will get incremeneted at the end of the // outter loop to skip the quote char } else { pos++; } } } else if ( buf[pos] == '>' ) { return ""; } } pos++; } return ""; } std::string Cal3dFilter::readXElement( const char * tag ) { const char * buf = (const char *) m_fileBuf; size_t pos = m_bufPos - m_fileBuf; std::string endTag = std::string( "/" ) + tag; size_t tagLen = endTag.size(); bool inTag = true; size_t start = 0; while ( pos < m_fileLength - 1 ) { if ( inTag ) { if ( buf[pos] == '/' && buf[pos+1] == '>' ) { m_bufPos = &m_fileBuf[pos+2]; return ""; } else if ( buf[pos] == '>' ) { inTag = false; start = pos + 1; } } else { if ( buf[pos] == '<' ) { if ( strncasecmp( &buf[pos+1], endTag.c_str(), tagLen ) == 0) { m_bufPos = &m_fileBuf[pos]; //log_debug( "found end of tag %s at %p\n", tag, m_bufPos ); std::string rval; rval.assign( &buf[ start ], pos - start ); //log_debug( "tag data: %s\n", rval.c_str() ); return rval; } } } pos++; } return ""; } //------------------------------------------------------------------ // Format write functions Model::ModelErrorE Cal3dFilter::writeCal3dFile( const char * filename, Model * model, ModelFilter::Options * o ) { Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; std::string base = m_modelPath + "/"; // Use dynamic cast to determine if the object is of the proper type // If not, create new one that we will delete later. // // We need to create one to make sure that the default options we // use in the filter match the default options presented to the // user in the dialog box. m_options = dynamic_cast< Cal3dOptions *>( o ); release_ptr freeOptions = NULL; if ( !m_options ) { freeOptions = static_cast( getDefaultOptions() ); m_options = freeOptions.get(); } m_model->updateMetaData( "cal3d_single_mesh_file", m_options->m_singleMeshFile ? "1" : "0" ); m_model->updateMetaData( "cal3d_xml_material", m_options->m_xmlMatFile ? "1" : "0" ); m_dst->writeString( "#\n# cal3d model configuration file\n#\n" ); m_dst->writeString( "# File written by Misfit Model 3D\n" ); m_dst->writeString( "# https://clover.com/mm3d\n\n" ); m_dst->writeString( "[model]\n" ); char value[64]; if ( m_model->getMetaData( "cal3d_path", value, sizeof(value) ) ) { m_dst->writePrintf( "path=\"%s\"\n", value ); } if ( m_model->getMetaData( "cal3d_scale", value, sizeof(value) ) ) { m_dst->writePrintf( "scale=\"%s\"\n", value ); } if ( m_model->getMetaData( "cal3d_rotate", value, sizeof(value) ) ) { m_dst->writePrintf( "rotate=\"%s\"\n", value ); } m_dst->writeString( "\n# --- Skeleton ---\n" ); std::string skelFile = replaceExtension( m_modelBaseName.c_str(), "csf" ); m_dst->writePrintf( "skeleton = \"%s\"\n\n", skelFile.c_str() ); writeSkeletonFile( (base + skelFile).c_str(), model ); // To write animations: // // * Make a map of filenames written (case-sensitive) // and map of animations written. // // * Run through meta data and write file if not already // in map. // // * Run through animations. If any not written, write them // and create an animation line in the Cal3D file. typedef std::map AnimFileMap; AnimFileMap fileWritten; std::vector animWritten; animWritten.resize( model->getAnimCount( MODE ) ); m_dst->writePrintf( "# --- Animations ---\n" ); std::string animFile; char keyStr[PATH_MAX]; char valueStr[PATH_MAX]; unsigned int mtcount = model->getMetaDataCount(); for ( unsigned int mt = 0; mt < mtcount; mt++ ) { model->getMetaData( mt, keyStr, PATH_MAX, valueStr, PATH_MAX ); if ( strncmp(keyStr, "animation_", 10 ) == 0 ) { animFile = valueStr; std::string animName = removeExtension( valueStr ); int a = findAnimation( animName ); if ( a >= 0 && fileWritten.find(animFile) == fileWritten.end() ) { writeAnimationFile( (base + animFile).c_str(), model, a ); animWritten[a] = true; fileWritten[animFile] = true; } m_dst->writePrintf( "%s = \"%s\"\n", keyStr, animFile.c_str() ); } } unsigned int acount = model->getAnimCount( MODE ); for ( unsigned int a = 0; a < acount; a++ ) { if ( animWritten[a] == 0 ) { const char * animName = model->getAnimName( MODE, a ); animFile = animName; animFile = addExtension( animFile, "caf" ); m_dst->writePrintf( "animation_%s = \"%s\"\n", animName, animFile.c_str() ); writeAnimationFile( (base + animFile).c_str(), model, a ); animWritten[a] = 1; } } m_dst->writeString( "\n" ); // Create meshes split on groups, with UVs and // normals unique to each vertex MeshList ml; mesh_create_list( ml, model ); m_dst->writeString( "# --- Meshes ---\n" ); if ( (m_options == NULL) || m_options->m_singleMeshFile ) { std::string meshFile = replaceExtension( m_modelBaseName.c_str(), "cmf" ); m_dst->writePrintf( "mesh_file = \"%s\"\n", meshFile.c_str() ); writeMeshListFile( (base + meshFile).c_str(), model, ml ); } else { std::string meshName; std::string meshFile; unsigned int meshCount = ml.size(); unsigned int meshNum; typedef std::map FileMeshMap; FileMeshMap fmm; string groupName; for ( meshNum = 0; meshNum < meshCount; meshNum++ ) { groupName = m_model->getGroupName(ml[meshNum].group); _strtolower( groupName ); fmm[ groupName ].push_back( ml[meshNum] ); } // Write the meshes for each group for ( FileMeshMap::const_iterator fmm_it = fmm.begin(); fmm_it != fmm.end(); fmm_it++ ) { // Get a count of how many meshes make up this group // (probably 1, but you never know) string groupName = fmm_it->first; const MeshList & groupMeshList = fmm_it->second; // Create mesh name and filename strings string meshName = groupName; string meshFile = groupName + ".cmf"; _escapeCal3dName(meshName); _escapeFileName(meshFile); // Write mesh file m_dst->writePrintf( "mesh_%s = \"%s\"\n", meshName.c_str(), meshFile.c_str() ); writeMeshListFile( (base + meshFile).c_str(), model, groupMeshList ); } } m_dst->writeString( "\n# --- Materials ---\n" ); std::string matFile; unsigned int mcount = model->getTextureCount(); for ( unsigned int m = 0; m < mcount; m++ ) { const char * matName = model->getTextureName( m ); matFile = matName; if ( m_options && !m_options->m_xmlMatFile ) { matFile += ".crf"; writeMaterialFile( (base + matFile).c_str(), model, m ); } else { matFile += ".xrf"; writeXMaterialFile( (base + matFile).c_str(), model, m ); } m_dst->writePrintf( "material_%s = \"%s\"\n", matName, matFile.c_str() ); } m_dst->writeString( "\n" ); m_options = NULL; return err; } Model::ModelErrorE Cal3dFilter::writeXMaterialFile( const char * filename, Model * model, unsigned int materialId ) { DataDest * oldDst = m_dst; Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; // Header int version = CAL3D_MIN_XVERSION; char versionStr[32]; if ( model->getMetaData( "cal3d_xrf_version", versionStr, sizeof(versionStr) ) ) { version = atoi(versionStr); } if ( version < CAL3D_NO_XHEADER_VERSION ) m_dst->writePrintf( "
\n", version ); Model::Material::MaterialTypeE type = model->getMaterialType( materialId ); // Start material element m_dst->writePrintf( "= CAL3D_NO_XHEADER_VERSION ) m_dst->writePrintf( " VERSION=\"%d\"", version ); m_dst->writePrintf( ">\n" ); // Material lighting properties float fval[4]; model->getTextureAmbient( materialId, fval ); writeXColor( "AMBIENT", fval ); model->getTextureDiffuse( materialId, fval ); writeXColor( "DIFFUSE", fval ); model->getTextureSpecular( materialId, fval ); writeXColor( "SPECULAR", fval ); model->getTextureShininess( materialId, fval[0] ); m_dst->writePrintf( " %f\n", fval[0] ); // Texture map if ( type == Model::Material::MATTYPE_TEXTURE ) { std::string textureFile = model->getTextureFilename( materialId ); std::string fullName; std::string fullPath; std::string baseName; normalizePath( filename, fullName, fullPath, baseName ); std::string relativeFile = getRelativePath( fullPath.c_str(), textureFile.c_str() ); m_dst->writePrintf( " %s\n", relativeFile.c_str() ); } // close material element m_dst->writePrintf( "\n" ); m_dst = oldDst; return err; } Model::ModelErrorE Cal3dFilter::writeSkeletonFile( const char * filename, Model * model ) { DataDest * oldDst = m_dst; Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; unsigned int bcount = model->getBoneJointCount(); int32_t version = CAL3D_MIN_BVERSION; char versionStr[32]; if ( model->getMetaData( "cal3d_binary_version", versionStr, sizeof(versionStr) ) ) { version = atoi(versionStr); } // Header m_dst->writeBytes( (uint8_t *) CAL3D_MAGIC_SKELETON, CAL3D_MAGIC_SIZE ); m_dst->write( version ); m_dst->write( (int32_t) bcount ); for ( unsigned int b = 0; b < bcount; b++ ) { writeBBone( b ); } m_dst = oldDst; return err; } Model::ModelErrorE Cal3dFilter::writeMeshFile( const char * filename, Model * model ) { // Create a list of all meshes MeshList ml; mesh_create_list( ml, model ); return writeMeshListFile( filename, model, ml ); } Model::ModelErrorE Cal3dFilter::writeMeshListFile( const char * filename, Model * model, const MeshList & meshList ) { DataDest * oldDst = m_dst; Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; int32_t version = CAL3D_MIN_BVERSION; char versionStr[32]; if ( model->getMetaData( "cal3d_binary_version", versionStr, sizeof(versionStr) ) ) { version = atoi(versionStr); } // Header m_dst->writeBytes( (uint8_t *) CAL3D_MAGIC_MESH, CAL3D_MAGIC_SIZE ); m_dst->write( version ); m_dst->write( (int32_t) meshList.size() ); // Save mesh to file log_debug( "writing mesh file %s\n", filename ); MeshList::const_iterator mit; for ( mit = meshList.begin(); mit != meshList.end(); mit++ ) { log_debug( " writing a mesh\n" ); writeBMesh( *mit ); } m_dst = oldDst; return err; } Model::ModelErrorE Cal3dFilter::writeMaterialFile( const char * filename, Model * model, unsigned int materialId ) { DataDest * oldDst = m_dst; Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; // Header m_dst->writeBytes( (uint8_t *) CAL3D_MAGIC_MATERIAL, CAL3D_MAGIC_SIZE ); int32_t version = CAL3D_MIN_BVERSION; char versionStr[32]; if ( model->getMetaData( "cal3d_binary_version", versionStr, sizeof(versionStr) ) ) { version = atoi(versionStr); } m_dst->write( version ); // Material lighting properties float fval[4]; model->getTextureAmbient( materialId, fval ); writeBColor( fval ); model->getTextureDiffuse( materialId, fval ); writeBColor( fval ); model->getTextureSpecular( materialId, fval ); writeBColor( fval ); model->getTextureShininess( materialId, fval[0] ); m_dst->write( (float32_t) fval[0] ); // Texture map if ( model->getMaterialType( materialId ) == Model::Material::MATTYPE_TEXTURE ) { m_dst->write( (int32_t) 1 ); std::string textureFile = model->getTextureFilename( materialId ); std::string fullName; std::string fullPath; std::string baseName; normalizePath( filename, fullName, fullPath, baseName ); std::string relativeFile = getRelativePath( fullPath.c_str(), textureFile.c_str() ); writeBString( relativeFile ); } else { m_dst->write( (int32_t) 0 ); } m_dst = oldDst; return err; } Model::ModelErrorE Cal3dFilter::writeAnimationFile( const char * filename, Model * model, unsigned int animationId ) { DataDest * oldDst = m_dst; Model::ModelErrorE err = Model::ERROR_NONE; m_dst = openOutput( filename, err ); DestCloser fc( m_dst ); if ( err != Model::ERROR_NONE ) return err; // get anim header info float fps = model->getAnimFPS( MODE, animationId ); unsigned int frameCount = model->getAnimFrameCount( MODE, animationId ); float32_t duration = (double) frameCount / fps; if ( frameCount > 0 ) { duration = ((double) frameCount - 1) / fps; } // build track list std::list tracks; bool found = false; double kf[3]; unsigned int bcount = model->getBoneJointCount(); for ( unsigned int b = 0; b < bcount; b++ ) { found = false; for ( unsigned int f = 0; !found && f < frameCount; f++ ) { if ( model->getSkelAnimKeyframe( animationId, f, b, false, kf[0], kf[1], kf[2] ) || model->getSkelAnimKeyframe( animationId, f, b, true, kf[0], kf[1], kf[2] ) ) { found = true; tracks.push_back( b ); } } } int32_t version = CAL3D_MIN_BVERSION; char versionStr[32]; if ( model->getMetaData( "cal3d_binary_version", versionStr, sizeof(versionStr) ) ) { version = atoi(versionStr); } // write header m_dst->writeBytes( (uint8_t *) CAL3D_MAGIC_ANIMATION, CAL3D_MAGIC_SIZE ); m_dst->write( version ); m_dst->write( duration ); m_dst->write( (int32_t) tracks.size() ); if ( version >= CAL3D_COMP_ANIM_VERSION ) { // Flags, no compression m_dst->write( (int32_t) 0 ); } // write tracks std::list::iterator it; for ( it = tracks.begin(); it != tracks.end(); it++ ) { writeBAnimTrack( animationId, *it ); } m_dst = oldDst; return err; } void Cal3dFilter::writeBBone( unsigned int b ) { std::string name = m_model->getBoneJointName( b ); writeBString( name ); Matrix m; m_model->getBoneJointAbsoluteMatrix( b, m ); Matrix pinv; int parent = m_model->getBoneJointParent( b ); if ( parent >= 0 ) { m_model->getBoneJointAbsoluteMatrix( parent, pinv ); pinv = pinv.getInverse(); } Matrix lm; lm = m * pinv; Vector trans; Quaternion rot; lm.getTranslation( trans ); lm.getRotationQuaternion( rot ); rot = rot.swapHandedness(); writeBVector3( trans ); // relative to parent writeBQuaternion( rot ); m = m.getInverse(); m.getTranslation( trans ); m.getRotationQuaternion( rot ); rot = rot.swapHandedness(); writeBVector3( trans ); // model space writeBQuaternion( rot ); // write parent m_dst->write( (int32_t) parent ); // find children std::list children; unsigned bcount = m_model->getBoneJointCount(); for ( unsigned int child = 0; child < bcount; child++ ) { int cparent = m_model->getBoneJointParent( child ); if ( (unsigned int) cparent == b ) { children.push_back( child ); } } // write children m_dst->write( (int32_t) children.size() ); std::list::iterator it; for ( it = children.begin(); it != children.end(); it++ ) { m_dst->write( (int32_t) *it ); } } void Cal3dFilter::writeBAnimTrack( unsigned int anim, unsigned int bone ) { float fps = m_model->getAnimFPS( MODE, anim ); unsigned int frameCount = m_model->getAnimFrameCount( MODE, anim ); std::list frames; double kf[3]; for ( unsigned int f = 0; f < frameCount; f++ ) { if ( m_model->getSkelAnimKeyframe( anim, f, bone, false, kf[0], kf[1], kf[2] ) || m_model->getSkelAnimKeyframe( anim, f, bone, true, kf[0], kf[1], kf[2] ) ) { frames.push_back( f ); } } // write track info m_dst->write( (int32_t) bone ); m_dst->write( (int32_t) frames.size() ); // write keyframe data std::list::iterator it; for ( it = frames.begin(); it != frames.end(); it++ ) { double frameTime = ((double) (*it)) / fps; m_dst->write( (float32_t) frameTime ); // MM3D allows one type of keyframe without the other, Cal3D requires // both rotation and translation for each keyframe. If we have one // and the other is missing, we must do interpolation here. Matrix m; m_model->interpSkelAnimKeyframeTime( anim, frameTime, true, bone, m ); Matrix rm; m_model->getBoneJointRelativeMatrix( bone, rm ); m = m * rm; Vector trans; Quaternion rot; m.getRotationQuaternion( rot ); m.getTranslation( trans ); rot = rot.swapHandedness(); writeBVector3( trans ); writeBQuaternion( rot ); } } void Cal3dFilter::writeBMesh( const Mesh & mesh ) { int materialId = -1; if ( mesh.group >= 0 ) { materialId = m_model->getGroupTextureId( mesh.group ); } m_dst->write( (int32_t) materialId ); m_dst->write( (int32_t) mesh.vertices.size() ); m_dst->write( (int32_t) mesh.faces.size() ); m_dst->write( (int32_t) 0 ); m_dst->write( (int32_t) 0 ); if ( materialId >= 0 ) { m_dst->write( (int32_t) 1 ); } else { m_dst->write( (int32_t) 0 ); } double coord[3]; Mesh::VertexList::const_iterator vit; for ( vit = mesh.vertices.begin(); vit != mesh.vertices.end(); vit++ ) { const Mesh::Vertex & mv = *vit; m_model->getVertexCoordsUnanimated( mv.v, coord ); m_dst->write( (float32_t) coord[0] ); m_dst->write( (float32_t) coord[1] ); m_dst->write( (float32_t) coord[2] ); m_dst->write( (float32_t) mv.norm[0] ); m_dst->write( (float32_t) mv.norm[1] ); m_dst->write( (float32_t) mv.norm[2] ); m_dst->write( (int32_t) -1 ); m_dst->write( (int32_t) 0 ); if ( materialId >= 0 ) { m_dst->write( (float32_t) mv.uv[0] ); m_dst->write( (float32_t) mv.uv[1] ); } Model::InfluenceList il; Model::InfluenceList::iterator it; m_model->getVertexInfluences( mv.v, il ); // Our weights don't always equal 100%, get total weigth so we can normalize double total = 0.0; for ( it = il.begin(); it != il.end(); it++ ) { total += it->m_weight; } // Don't allow negative weights, or divide by zero if ( total < 0.0005 ) { total = 1.0; } // Write out influence list m_dst->write( (int32_t) il.size() ); // number of influences for ( it = il.begin(); it != il.end(); it++ ) { m_dst->write( (int32_t) it->m_boneId ); // bone m_dst->write( (float32_t) (it->m_weight / total) ); // normalized weight } // No springs, don't need to write weight } // Write springs... we don't have any... don't write anything // Write faces Mesh::FaceList::const_iterator fit; for ( fit = mesh.faces.begin(); fit != mesh.faces.end(); fit++ ) { const Mesh::Face & mf = *fit; m_dst->write( (int32_t) mf.v[0] ); m_dst->write( (int32_t) mf.v[1] ); m_dst->write( (int32_t) mf.v[2] ); } } //------------------------------------------------------------------ // Binary write functions void Cal3dFilter::writeBVector3( const Vector & vec ) { m_dst->write( (float32_t) vec[0] ); m_dst->write( (float32_t) vec[1] ); m_dst->write( (float32_t) vec[2] ); } void Cal3dFilter::writeBQuaternion( const Quaternion & quat ) { m_dst->write( (float32_t) quat[0] ); m_dst->write( (float32_t) quat[1] ); m_dst->write( (float32_t) quat[2] ); m_dst->write( (float32_t) quat[3] ); } void Cal3dFilter::writeBString( const std::string & str ) { // Include NULL byte in write uint32_t len = str.size() + 1; m_dst->write( len ); m_dst->writeBytes( (uint8_t *) str.c_str(), len ); } void Cal3dFilter::writeBColor( const float * fval ) { uint32_t dval; for ( int i = 0; i < 4; i++ ) { dval = (uint32_t) (fval[i] * 255.0); if ( dval > 255 ) { dval = 255; } m_dst->write( (uint8_t) dval ); } } void Cal3dFilter::writeXColor( const char * tag, const float * fval ) { m_dst->writePrintf( " <%s>", tag ); uint32_t dval; for ( int i = 0; i < 4; i++ ) { dval = (uint32_t) (fval[i] * 255.0); if ( dval > 255 ) { dval = 255; } m_dst->writePrintf( "%d%s", dval, (i < 3) ? " " : "" ); } m_dst->writePrintf( "\n", tag ); } int Cal3dFilter::timeToFrame( double tsec, double fps ) { int frame = 0; while ( (frame / fps) < (tsec - 0.0005f) ) { frame++; } //log_debug( " time %f is frame %d\n", tsec, frame ); return frame; } int Cal3dFilter::findAnimation( const std::string& animName ) { int acount = m_model->getAnimCount( MODE ); for ( int a = 0; a < acount; a++ ) { if ( strcasecmp( animName.c_str(), m_model->getAnimName( MODE, a ) ) == 0 ) { return a; } } return -1; } #ifdef PLUGIN //------------------------------------------------------------------ // Plugin functions //------------------------------------------------------------------ extern "C" bool plugin_init() { if ( s_filter == NULL ) { s_filter = new Cal3dFilter(); FilterManager * texmgr = FilterManager::getInstance(); texmgr->registerFilter( s_filter ); } log_debug( "CAL3D model filter plugin initialized\n" ); return true; } // The filter manager will delete our registered filter. // We have no other cleanup to do extern "C" bool plugin_uninit() { s_filter = NULL; // FilterManager deletes filters log_debug( "CAL3D model filter plugin uninitialized\n" ); return true; } extern "C" const char * plugin_version() { return "0.1.0"; } extern "C" const char * plugin_desc() { return "CAL3D model filter"; } #endif // PLUGIN mm3d-master/src/libmm3d/cal3dfilter.h000066400000000000000000000150111324021725400176700ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CAL3DFILTER_H #define __CAL3DFILTER_H #include "modelfilter.h" #include "mesh.h" #include #include #include #include #include #include #include class Cal3dFilter : public ModelFilter { public: // The default values for the filter options are in // the constructor. class Cal3dOptions : public ModelFilter::Options { public: Cal3dOptions(); bool m_singleMeshFile; bool m_xmlMatFile; void setOptionsFromModel( Model * m ); protected: virtual ~Cal3dOptions(); // Use release() instead }; Cal3dFilter(); virtual ~Cal3dFilter(); Model::ModelErrorE readFile( Model * model, const char * const filename ); Model::ModelErrorE writeFile( Model * model, const char * const filename, ModelFilter::Options * o ); bool canRead( const char * filename ); bool canWrite( const char * filename ); bool canExport( const char * filename ); bool isSupported( const char * filename ); std::list< std::string > getReadTypes(); std::list< std::string > getWriteTypes(); ModelFilter::Options * getDefaultOptions() { return new Cal3dOptions; }; struct _UVData_t { float u; float v; }; typedef struct _UVData_t UVDataT; typedef std::vector< UVDataT > UVList; protected: enum _FileType_e { FT_Any, FT_Skeleton, FT_Animation, FT_Mesh, FT_Material, FT_MAX, }; typedef enum _FileType_e FileTypeE; static bool listHas( const std::list & l, const std::string & val ); static std::string addExtension( const std::string file, const std::string ext ); static bool versionIsValid( FileTypeE type, int version ); static bool xversionIsValid( FileTypeE type, int version ); // Sub file reads Model::ModelErrorE readSubFile( const char * filename ); Model::ModelErrorE readXSubFile( uint8_t * buf, size_t len ); Model::ModelErrorE readCal3dFile( uint8_t * buf, size_t len ); Model::ModelErrorE readSkeletonFile( uint8_t * buf, size_t len ); Model::ModelErrorE readMeshFile( uint8_t * buf, size_t len ); Model::ModelErrorE readMaterialFile( uint8_t * buf, size_t len ); Model::ModelErrorE readXMaterialFile( uint8_t * buf, size_t len ); Model::ModelErrorE readAnimationFile( uint8_t * buf, size_t len ); // Common read functions Model::ModelErrorE readFileToBuffer( const char * filename, uint8_t * & buf, size_t & len ); void freeFileBuffer( uint8_t * buf ); uint8_t readBUInt8(); int16_t readBInt16(); int32_t readBInt32(); uint64_t readBUInt48(); float readBFloat(); Vector readBVector3(); Vector readBVector4(); bool readBString( std::string & ); bool readBLine( std::string &, size_t maxLen ); // common XML reading functions bool findXElement( const char * tag ); // Finds an XML element by tag std::string readXAttribute( const char * attr ); // Read a specified attribute of the current element std::string readXElement( const char * tag ); // Read the contents of the XML tag (if any) Vector readAVector3( const char * str ); Vector readAVector4( const char * str ); std::string readAString( const char * str ); bool readBBone(); bool readBSubMesh(); bool readBAnimTrack(); bool readBCompressedAnimTrack( double duration ); std::string readLineKey( const char * str ); std::string readLineFile( const char * str ); // binary sub file writes Model::ModelErrorE writeCal3dFile( const char * filename, Model * model, ModelFilter::Options * o ); Model::ModelErrorE writeSkeletonFile( const char * filename, Model * model ); Model::ModelErrorE writeMeshFile( const char * filename, Model * model ); Model::ModelErrorE writeMeshListFile( const char * filename, Model * model, const MeshList & meshList ); Model::ModelErrorE writeMaterialFile( const char * filename, Model * model, unsigned int materialId ); Model::ModelErrorE writeAnimationFile( const char * filename, Model * model, unsigned int animationId ); // XML sub file writes Model::ModelErrorE writeXMaterialFile( const char * filename, Model * model, unsigned int materialId ); // Common binary write functions void writeBVector3( const Vector & vec ); void writeBQuaternion( const Quaternion & quat ); void writeBString( const std::string & ); void writeBColor( const float * fval ); void writeBBone( unsigned int b ); void writeBAnimTrack( unsigned int anim, unsigned int bone ); void writeBMesh( const Mesh & mesh ); // Common XML write functions void writeXColor( const char * tag, const float * fval ); int timeToFrame( double tsec, double fps ); int findAnimation( const std::string& animName ); Model * m_model; Cal3dOptions * m_options; DataDest * m_dst; uint8_t * m_bufPos; uint8_t * m_fileBuf; size_t m_fileLength; int m_anim; bool m_isBinary; bool m_isLittleEndian; int m_maxBinaryVersion; int m_maxXrfVersion; std::string m_modelPath; std::string m_modelBaseName; std::string m_modelFullName; std::string m_currentPath; std::string m_modelPartName; std::string m_modelPartExt; std::list m_formats; }; #endif // __CAL3DFILTER_H mm3d-master/src/libmm3d/cmdlinemgr.cc000066400000000000000000000146501324021725400177630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cmdlinemgr.h" #include namespace { class FunctionOption : public CommandLineManager::Option { public: FunctionOption( char shortOption, const char * longOption, bool takesArg, CommandLineManager::OptionFunctionF optFunc ) : CommandLineManager::Option( shortOption, longOption, NULL, takesArg ), m_optFunc( optFunc ) { } virtual ~FunctionOption() { } void customParse( const char * arg ) { if ( m_optFunc ) m_optFunc( arg ); } private: CommandLineManager::OptionFunctionF m_optFunc; }; } // namespace CommandLineManager::Option::Option( char shortOption, const char * longOption, const char * defaultValue, bool takesArg ) : m_shortOption( shortOption ), m_longOption( longOption ), m_takesArg( takesArg ), m_isSpecified( false ), m_intValue( 0 ), m_stringValue( "" ) { if ( defaultValue ) { m_stringValue = defaultValue; m_intValue = atoi( defaultValue ); } } CommandLineManager::Option::~Option() { } void CommandLineManager::Option::parseOption( const char * arg ) { if ( arg ) { m_isSpecified = true; m_stringValue = arg; m_intValue = atoi( arg ); customParse( arg ); } } void CommandLineManager::Option::customParse( const char * arg ) { // Do nothing } CommandLineManager::CommandLineManager() : m_uniqueId( 0 ), m_firstArg( 1 ), m_error( NoError ), m_errorArg( 0 ) { } CommandLineManager::~CommandLineManager() { } bool CommandLineManager::parse( int argc, const char ** argv ) { for ( int a = 1; a < argc; a++ ) { const char * str = argv[a]; // If this string doesn't start with a dash, or is just a single // dash (stdin as file input), then we're done. if ( str[0] != '-' || str[1] == '\0' ) { m_firstArg = a; return true; } if ( strcmp("--", str) == 0 ) { // End of options m_firstArg = a + 1; return true; } Option * opt = NULL; const char * arg = NULL; int nextOpt = a; // It is an option if ( str[1] == '-' ) { // Long option std::string longOpt = &str[2]; const char * end = strchr( str, '=' ); if ( end ) { arg = end + 1; longOpt.resize( end - &str[2] ); } else { arg = argv[a+1]; nextOpt = a + 1; } opt = lookupOptionByLong( longOpt.c_str() ); } else { // Short option const char * end = strchr( str, '=' ); if ( end ) { arg = end + 1; } else { arg = argv[a+1]; nextOpt = a + 1; } opt = lookupOptionByShort( str[1] ); } if ( !opt ) { m_error = UnknownOption; m_errorArg = a; return false; } if ( opt->takesArgument() ) { a = nextOpt; if ( a >= argc ) { m_error = MissingArgument; m_errorArg = a - 1; return false; } } else { arg = ""; } opt->parseOption( arg ); } // Ran out of command line options, there are no arguments m_firstArg = argc; return true; } void CommandLineManager::addOption( int id, char shortOption, const char * longOption, const char * defaultValue, bool takesArg ) { m_optionList[ id ] = new Option( shortOption, longOption, defaultValue, takesArg ); } void CommandLineManager::addCustomOption( int id, Option * opt ) { m_optionList[ id ] = opt; } void CommandLineManager::addFunctionOption( int id, char shortOption, const char * longOption, bool takesArg, OptionFunctionF optFunc ) { m_optionList[ id ] = new FunctionOption( shortOption, longOption, takesArg, optFunc ); } bool CommandLineManager::isSpecified( int optionId ) const { const Option * opt = lookupOptionById( optionId ); if ( opt ) return opt->isSpecified(); return false; } int CommandLineManager::intValue( int optionId ) const { const Option * opt = lookupOptionById( optionId ); if ( opt ) return opt->intValue(); return 0; } const char * CommandLineManager::stringValue( int optionId ) const { const Option * opt = lookupOptionById( optionId ); if ( opt ) return opt->stringValue(); return ""; } int CommandLineManager::getUniqueId() { return --m_uniqueId; } const CommandLineManager::Option * CommandLineManager::lookupOptionById( int optionId ) const { OptionListT::const_iterator it = m_optionList.find( optionId ); if ( it != m_optionList.end() ) return it->second.get(); else return NULL; } CommandLineManager::Option * CommandLineManager::lookupOptionByShort( char shortOption ) { for ( OptionListT::iterator it = m_optionList.begin(); it != m_optionList.end(); ++it ) { const char opt = it->second->shortOption(); if ( opt != 0 && opt == shortOption ) { return it->second.get(); } } return NULL; } CommandLineManager::Option * CommandLineManager::lookupOptionByLong( const char * longOption ) { for ( OptionListT::iterator it = m_optionList.begin(); it != m_optionList.end(); ++it ) { const char * opt = it->second->longOption(); if ( opt && strcmp( opt, longOption ) == 0 ) { return it->second.get(); } } return NULL; } mm3d-master/src/libmm3d/cmdlinemgr.h000066400000000000000000000066401324021725400176250ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef CMDLINEMGR_H_INC__ #define CMDLINEMGR_H_INC__ #include #include #include "local_ptr.h" class CommandLineManager { public: class Option { public: Option( char shortOption, const char * longOption = NULL, const char * defaultValue = NULL, bool takesArg = false ); virtual ~Option(); char shortOption() const { return m_shortOption; } const char * longOption() const { return m_longOption; } bool takesArgument() const { return m_takesArg; } void parseOption(const char * arg); int intValue() const { return m_intValue; } const char * stringValue() const { return m_stringValue.c_str(); } bool isSpecified() const { return m_isSpecified; } protected: void setIntValue(int val) { m_intValue = val; } void setStringValue(const char * val) { m_stringValue = val; } virtual void customParse(const char * arg); private: char m_shortOption; const char * m_longOption; bool m_takesArg; bool m_isSpecified; int m_intValue; std::string m_stringValue; }; enum ErrorE { NoError, UnknownOption, MissingArgument, }; typedef void (*OptionFunctionF)(const char *); CommandLineManager(); virtual ~CommandLineManager(); bool parse( int argc, const char ** argv ); int firstArgument() const { return m_firstArg; } ErrorE error() const { return m_error; } int errorArgument() const { return m_errorArg; } void addOption( int id, char shortOption, const char * longOption = NULL, const char * defaultValue = NULL, bool takesArg = false ); void addCustomOption( int id, Option * opt ); void addFunctionOption( int id, char shortOption, const char * longOption, bool takesArg, OptionFunctionF optFunc ); bool isSpecified( int optionId ) const; int intValue( int optionId ) const; const char * stringValue( int optionId ) const; int getUniqueId(); private: typedef std::map< int, local_ptr
$alt
END_OF_HTML ; } elsif ($width == 100) { # Full coverage $graph_code = (<$alt END_OF_HTML ; } else { # Positive coverage $graph_code = (<$alt$alt END_OF_HTML ; } # Remove leading tabs from all lines $graph_code =~ s/^\t+//gm; chomp($graph_code); return($graph_code); } # # classify_coverage_rate(coverage_rate) # # Return the clasification ("Lo"|"Med"|"Hi") of a given coverage rate # sub classify_coverage_rate($) { my @pair = coverage_rate_helper($_[0]); return $pair[0]; } # # get_png_for_coverage_rate(coverage_rate) # # Return the name of the png corresponding to the given coverage rate # sub get_png_for_coverage_rate($) { my @pair = coverage_rate_helper($_[0]); return $pair[1]; } # # coverage_rate_helper(coverage_rate) # # Does the work for "classify_coverage_rate" and "get_png_for_coverage_rate". # sub coverage_rate_helper($) { my $rate = $_[0]; if ($rate < $med_limit) { return(("Lo","ruby.png")); } elsif ($rate < $hi_limit) { return(("Med","amber.png")); } else { return(("Hi","emerald.png")); } } # # write_html(filehandle, html_code) # # Write out HTML_CODE to FILEHANDLE while removing a leading tabulator mark # in each line of HTML_CODE. # sub write_html(*$) { local *HTML_HANDLE = $_[0]; my $html_code = $_[1]; # Remove leading tab from all lines $html_code =~ s/^\t//gm; print(HTML_HANDLE $html_code) or die("ERROR: cannot write HTML data ($!)\n"); } # # write_html_prolog(filehandle, base_dir, pagetitle) # # Write an HTML prolog common to all HTML files to FILEHANDLE. PAGETITLE will # be used as HTML page title. BASE_DIR contains a relative path which points # to the base directory. # sub write_html_prolog(*$$) { my $basedir = $_[1]; my $pagetitle = $_[2]; my $prolog; $prolog = $html_prolog; $prolog =~ s/\@pagetitle\@/$pagetitle/g; $prolog =~ s/\@basedir\@/$basedir/g; write_html($_[0], $prolog); } # # write_header_prolog(filehandle, base_dir) # # Write beginning of page header HTML code. # sub write_header_prolog(*$) { # ************************************************************* write_html($_[0], < $title END_OF_HTML ; # ************************************************************* } # # write_header_line(filehandle, item1, value1, [item2, value2]) # # Write a header line, containing of either one or two pairs "header item" # and "header value". # sub write_header_line(*$$;$$) { my $item1 = $_[1]; my $value1 = $_[2]; # Use GOTO to prevent indenting HTML with more than one tabs if (scalar(@_) > 3) { goto two_items } # ************************************************************* write_html($_[0], < END_OF_HTML ; return(); # ************************************************************* two_items: my $item2 = $_[3]; my $value2 = $_[4]; # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_header_epilog(filehandle, base_dir) # # Write end of page header HTML code. # sub write_header_epilog(*$) { # ************************************************************* write_html($_[0], <
$item1: $value1
$item1: $value1 $item2: $value2
END_OF_HTML ; # ************************************************************* } # # write_header_legend(filehandle, type) # # Write a legend describing the coloring of the code coverage. # sub write_header_legend(*$) { my $type = $_[1]; # type of page being generated my $legend_body; # main summary or subdirectory summary if ($type == 0 or $type == 1) { $legend_body = (< Low: 0% to $med_limit% Medium: $med_limit% to $hi_limit% High: $hi_limit% to 100% END_OF_HTML ; } # source code elsif ($type == 2) { my $legend_highlight; $legend_highlight = ""; if ($highlight) { $legend_highlight = (< converted-only END_OF_HTML ; } $legend_body = (< not executed executed $legend_highlight END_OF_HTML ; } # description file ($type == 3) else { return(); } # ************************************************************* write_html($_[0], < Legend: $legend_body END_OF_HTML ; return(); # ************************************************************* } # # write_file_table_prolog(filehandle, left_heading, right_heading) # # Write heading for file table. # sub write_file_table_prolog(*$$) { # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_file_table_entry(filehandle, cover_filename, cover_bar_graph, # cover_found, cover_hit) # # Write an entry of the file table. # sub write_file_table_entry(*$$$$) { my $rate; my $rate_string; my $classification = "Lo"; if ($_[3]>0) { $rate = $_[4] * 100 / $_[3]; $rate_string = sprintf("%.1f", $rate)." %"; $classification = classify_coverage_rate($rate); } else { $rate_string = "undefined"; } # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_file_table_detail_heading(filehandle, left_heading, right_heading) # # Write heading for detail section in file table. # sub write_file_table_detail_heading(*$$) { # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_file_table_detail_entry(filehandle, test_name, cover_found, cover_hit) # # Write entry for detail section in file table. # sub write_file_table_detail_entry(*$$$) { my $rate; my $name = $_[1]; if ($_[2]>0) { $rate = sprintf("%.1f", $_[3]*100/$_[2])." %"; } else { $rate = "undefined"; } if ($name =~ /^(.*),diff$/) { $name = $1." (converted)"; } if ($name eq "") { $name = "<unnamed>"; } # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_file_table_epilog(filehandle) # # Write end of file table HTML code. # sub write_file_table_epilog(*) { # ************************************************************* write_html($_[0], <
END_OF_HTML ; # ************************************************************* } # # write_test_table_prolog(filehandle, table_heading) # # Write heading for test case description table. # sub write_test_table_prolog(*$) { # ************************************************************* write_html($_[0], <

$_[1] $_[2]
$_[1] $_[2] $rate_string $_[4] / $_[3] lines
$_[1] $_[2]
$name $rate $_[3] / $_[2] lines

$_[1]
END_OF_HTML ; # ************************************************************* } # # write_test_table_entry(filehandle, test_name, test_description) # # Write entry for the test table. # sub write_test_table_entry(*$$) { # ************************************************************* write_html($_[0], <$_[1] 
$_[2]

END_OF_HTML ; # ************************************************************* } # # write_test_table_epilog(filehandle) # # Write end of test description table HTML code. # sub write_test_table_epilog(*) { # ************************************************************* write_html($_[0], <

END_OF_HTML ; # ************************************************************* } # # write_source_prolog(filehandle) # # Write start of source code table. # sub write_source_prolog(*) { # ************************************************************* write_html($_[0], <
END_OF_HTML
	;

	# *************************************************************
}


#
# write_source_line(filehandle, line_num, source, hit_count, converted)
#
# Write formatted source code line. Return a line in a format as needed
# by gen_png()
#

sub write_source_line(*$$$$)
{
	my $source_format;
	my $count;
	my $result;
	my $anchor_start = "";
	my $anchor_end = "";

	if (!(defined$_[3]))
	{
		$result		= "";
		$source_format	= "";
		$count		= " "x15;
	}
	elsif ($_[3] == 0)
	{
		$result		= $_[3];
		$source_format	= '';
		$count		= sprintf("%15d", $_[3]);
	}
	elsif ($_[4] && defined($highlight))
	{
		$result		= "*".$_[3];
		$source_format	= '';
		$count		= sprintf("%15d", $_[3]);
	}
	else
	{
		$result		= $_[3];
		$source_format	= '';
		$count		= sprintf("%15d", $_[3]);
	}

	$result .= ":".$_[2];

	# Write out a line number navigation anchor every $nav_resolution
	# lines if necessary
	if ($frames && (($_[1] - 1) % $nav_resolution == 0))
	{
		$anchor_start	= "";
		$anchor_end	= "";
	}


	# *************************************************************

	write_html($_[0],
		   $anchor_start.
		   ''.sprintf("%8d", $_[1]).
		   " $source_format$count : ".
		   escape_html($_[2]).($source_format?"":"").
		   $anchor_end."\n");

	# *************************************************************

	return($result);
}


#
# write_source_epilog(filehandle)
#
# Write end of source code table.
#

sub write_source_epilog(*)
{
	# *************************************************************

	write_html($_[0], <
	      
	    
	  
	  
END_OF_HTML ; # ************************************************************* } # # write_html_epilog(filehandle, base_dir[, break_frames]) # # Write HTML page footer to FILEHANDLE. BREAK_FRAMES should be set when # this page is embedded in a frameset, clicking the URL link will then # break this frameset. # sub write_html_epilog(*$;$) { my $basedir = $_[1]; my $break_code = ""; my $epilog; if (defined($_[2])) { $break_code = " target=\"_parent\""; } # ************************************************************* write_html($_[0], < Generated by: $lcov_version
END_OF_HTML ; $epilog = $html_epilog; $epilog =~ s/\@basedir\@/$basedir/g; write_html($_[0], $epilog); } # # write_frameset(filehandle, basedir, basename, pagetitle) # # sub write_frameset(*$$$) { my $frame_width = $overview_width + 40; # ************************************************************* write_html($_[0], < $_[3] <center>Frames not supported by your browser!<br></center> END_OF_HTML ; # ************************************************************* } # # sub write_overview_line(filehandle, basename, line, link) # # sub write_overview_line(*$$$) { my $y1 = $_[2] - 1; my $y2 = $y1 + $nav_resolution - 1; my $x2 = $overview_width - 1; # ************************************************************* write_html($_[0], < END_OF_HTML ; # ************************************************************* } # # write_overview(filehandle, basedir, basename, pagetitle, lines) # # sub write_overview(*$$$$) { my $index; my $max_line = $_[4] - 1; my $offset; # ************************************************************* write_html($_[0], < $_[3] END_OF_HTML ; # ************************************************************* # Make $offset the next higher multiple of $nav_resolution $offset = ($nav_offset + $nav_resolution - 1) / $nav_resolution; $offset = sprintf("%d", $offset ) * $nav_resolution; # Create image map for overview image for ($index = 1; $index <= $_[4]; $index += $nav_resolution) { # Enforce nav_offset if ($index < $offset + 1) { write_overview_line($_[0], $_[2], $index, 1); } else { write_overview_line($_[0], $_[2], $index, $index - $offset); } } # ************************************************************* write_html($_[0], <
Top

Overview
END_OF_HTML ; # ************************************************************* } # # write_header(filehandle, type, trunc_file_name, rel_file_name, lines_found, # lines_hit) # # Write a complete standard page header. TYPE may be (0, 1, 2, 3) # corresponding to (directory view header, file view header, source view # header, test case description header) # sub write_header(*$$$$$) { local *HTML_HANDLE = $_[0]; my $type = $_[1]; my $trunc_name = $_[2]; my $rel_filename = $_[3]; my $lines_found = $_[4]; my $lines_hit = $_[5]; my $base_dir; my $view; my $test; my $rate; my $base_name; # Calculate coverage rate if ($lines_found>0) { $rate = sprintf("%.1f", $lines_hit * 100 / $lines_found)." %"; } else { $rate = "-"; } $base_name = basename($rel_filename); # Prepare text for "current view" field if ($type == 0) { # Main overview $base_dir = ""; $view = $overview_title; } elsif ($type == 1) { # Directory overview $base_dir = get_relative_base_path($rel_filename); $view = "". "$overview_title - $trunc_name"; } elsif ($type == 2) { # File view my $dir_name = dirname($rel_filename); $base_dir = get_relative_base_path($dir_name); if ($frames) { # Need to break frameset when clicking any of these # links $view = "$overview_title - ". "". "$dir_name - $base_name"; } else { $view = "". "$overview_title - ". "". "$dir_name - $base_name"; } } elsif ($type == 3) { # Test description header $base_dir = ""; $view = "". "$overview_title - test case descriptions"; } # Prepare text for "test" field $test = escape_html($test_title); # Append link to test description page if available if (%test_description && ($type != 3)) { if ($frames && ($type == 2)) { # Need to break frameset when clicking this link $test .= " ( ". "view test case descriptions )"; } else { $test .= " ( ". "view test case descriptions )"; } } # Write header write_header_prolog(*HTML_HANDLE, $base_dir); write_header_line(*HTML_HANDLE, "Current view", $view); write_header_line(*HTML_HANDLE, "Test", $test); write_header_line(*HTML_HANDLE, "Date", $date, "Instrumented lines", $lines_found); write_header_line(*HTML_HANDLE, "Code covered", $rate, "Executed lines", $lines_hit); if ($legend) { write_header_legend(*HTML_HANDLE, $type); } write_header_epilog(*HTML_HANDLE, $base_dir); } # # split_filename(filename) # # Return (path, filename, extension) for a given FILENAME. # sub split_filename($) { if (!$_[0]) { return(); } my @path_components = split('/', $_[0]); my @file_components = split('\.', pop(@path_components)); my $extension = pop(@file_components); return (join("/",@path_components), join(".",@file_components), $extension); } # # write_file_table(filehandle, base_dir, overview, testhash, fileview) # # Write a complete file table. OVERVIEW is a reference to a hash containing # the following mapping: # # filename -> "lines_found,lines_hit,page_link" # # TESTHASH is a reference to the following hash: # # filename -> \%testdata # %testdata: name of test affecting this file -> \%testcount # %testcount: line number -> execution count for a single test # # Heading of first column is "Filename" if FILEVIEW is true, "Directory name" # otherwise. # sub write_file_table(*$$$$) { local *HTML_HANDLE = $_[0]; my $base_dir = $_[1]; my %overview = %{$_[2]}; my %testhash = %{$_[3]}; my $fileview = $_[4]; my $filename; my $bar_graph; my $hit; my $found; my $page_link; my $testname; my $testdata; my $testcount; my %affecting_tests; my $coverage_heading = "Coverage"; # Provide a link to details/non-detail list if this is directory # overview and we are supposed to create a detail view if (($base_dir ne "") && $show_details) { if (%testhash) { # This is the detail list, provide link to standard # list $coverage_heading .= " ( hide ". "details )"; } else { # This is the standard list, provide link to detail # list $coverage_heading .= " ( show ". "details )"; } } write_file_table_prolog(*HTML_HANDLE, $fileview ? "Filename" : "Directory name", $coverage_heading); foreach $filename (sort(keys(%overview))) { ($found, $hit, $page_link) = split(",", $overview{$filename}); $bar_graph = get_bar_graph_code($base_dir, $found, $hit); $testdata = $testhash{$filename}; # Add anchor tag in case a page link is provided if ($page_link) { $filename = "$filename"; } write_file_table_entry(*HTML_HANDLE, $filename, $bar_graph, $found, $hit); # Check whether we should write test specific coverage # as well if (!($show_details && $testdata)) { next; } # Filter out those tests that actually affect this file %affecting_tests = %{ get_affecting_tests($testdata) }; # Does any of the tests affect this file at all? if (!%affecting_tests) { next; } # Write test details for this entry write_file_table_detail_heading(*HTML_HANDLE, "Test name", "Lines hit"); foreach $testname (keys(%affecting_tests)) { ($found, $hit) = split(",", $affecting_tests{$testname}); # Insert link to description of available if ($test_description{$testname}) { $testname = "". "$testname"; } write_file_table_detail_entry(*HTML_HANDLE, $testname, $found, $hit); } } write_file_table_epilog(*HTML_HANDLE); } # # get_found_and_hit(hash) # # Return the count for entries (found) and entries with an execution count # greater than zero (hit) in a hash (linenumber -> execution count) as # a list (found, hit) # sub get_found_and_hit($) { my %hash = %{$_[0]}; my $found = 0; my $hit = 0; # Calculate sum $found = 0; $hit = 0; foreach (keys(%hash)) { $found++; if ($hash{$_}>0) { $hit++; } } return ($found, $hit); } # # get_affecting_tests(hashref) # # HASHREF contains a mapping filename -> (linenumber -> exec count). Return # a hash containing mapping filename -> "lines found, lines hit" for each # filename which has a nonzero hit count. # sub get_affecting_tests($) { my %hash = %{$_[0]}; my $testname; my $testcount; my %result; my $found; my $hit; foreach $testname (keys(%hash)) { # Get (line number -> count) hash for this test case $testcount = $hash{$testname}; # Calculate sum ($found, $hit) = get_found_and_hit($testcount); if ($hit>0) { $result{$testname} = "$found,$hit"; } } return(\%result); } # # write_source(filehandle, source_filename, count_data, checksum_data, # converted_data) # # Write an HTML view of a source code file. Returns a list containing # data as needed by gen_png(). # # Die on error. # sub write_source($$$$$) { local *HTML_HANDLE = $_[0]; local *SOURCE_HANDLE; my $source_filename = $_[1]; my %count_data; my $line_number; my @result; my $checkdata = $_[3]; my $converted = $_[4]; if ($_[2]) { %count_data = %{$_[2]}; } open(SOURCE_HANDLE, "<".$source_filename) or die("ERROR: cannot open $source_filename for reading!\n"); write_source_prolog(*HTML_HANDLE); for ($line_number = 1; ; $line_number++) { chomp($_); # Source code matches coverage data? if (defined($checkdata->{$line_number}) && ($checkdata->{$line_number} ne md5_base64($_))) { die("ERROR: checksum mismatch at $source_filename:". "$line_number\n"); } push (@result, write_source_line(HTML_HANDLE, $line_number, $_, $count_data{$line_number}, $converted->{$line_number})); } close(SOURCE_HANDLE); write_source_epilog(*HTML_HANDLE); return(@result); } # # info(printf_parameter) # # Use printf to write PRINTF_PARAMETER to stdout only when the $quiet flag # is not set. # sub info(@) { if (!$quiet) { # Print info string printf(@_); } } # # subtract_counts(data_ref, base_ref) # sub subtract_counts($$) { my %data = %{$_[0]}; my %base = %{$_[1]}; my $line; my $data_count; my $base_count; my $hit = 0; my $found = 0; foreach $line (keys(%data)) { $found++; $data_count = $data{$line}; $base_count = $base{$line}; if (defined($base_count)) { $data_count -= $base_count; # Make sure we don't get negative numbers if ($data_count<0) { $data_count = 0; } } $data{$line} = $data_count; if ($data_count > 0) { $hit++; } } return (\%data, $found, $hit); } # # add_counts(data1_ref, data2_ref) # # DATA1_REF and DATA2_REF are references to hashes containing a mapping # # line number -> execution count # # Return a list (RESULT_REF, LINES_FOUND, LINES_HIT) where RESULT_REF # is a reference to a hash containing the combined mapping in which # execution counts are added. # sub add_counts($$) { my %data1 = %{$_[0]}; # Hash 1 my %data2 = %{$_[1]}; # Hash 2 my %result; # Resulting hash my $line; # Current line iteration scalar my $data1_count; # Count of line in hash1 my $data2_count; # Count of line in hash2 my $found = 0; # Total number of lines found my $hit = 0; # Number of lines with a count > 0 foreach $line (keys(%data1)) { $data1_count = $data1{$line}; $data2_count = $data2{$line}; # Add counts if present in both hashes if (defined($data2_count)) { $data1_count += $data2_count; } # Store sum in %result $result{$line} = $data1_count; $found++; if ($data1_count > 0) { $hit++; } } # Add lines unique to data2 foreach $line (keys(%data2)) { # Skip lines already in data1 if (defined($data1{$line})) { next; } # Copy count from data2 $result{$line} = $data2{$line}; $found++; if ($result{$line} > 0) { $hit++; } } return (\%result, $found, $hit); } # # apply_baseline(data_ref, baseline_ref) # # Subtract the execution counts found in the baseline hash referenced by # BASELINE_REF from actual data in DATA_REF. # sub apply_baseline($$) { my %data_hash = %{$_[0]}; my %base_hash = %{$_[1]}; my $filename; my $testname; my $data; my $data_testdata; my $data_funcdata; my $data_checkdata; my $data_count; my $base; my $base_testdata; my $base_checkdata; my $base_count; my $sumcount; my $found; my $hit; foreach $filename (keys(%data_hash)) { # Get data set for data and baseline $data = $data_hash{$filename}; $base = $base_hash{$filename}; # Get set entries for data and baseline ($data_testdata, undef, $data_funcdata, $data_checkdata) = get_info_entry($data); ($base_testdata, $base_count, undef, $base_checkdata) = get_info_entry($base); # Check for compatible checksums merge_checksums($data_checkdata, $base_checkdata, $filename); # Sumcount has to be calculated anew $sumcount = {}; # For each test case, subtract test specific counts foreach $testname (keys(%{$data_testdata})) { # Get counts of both data and baseline $data_count = $data_testdata->{$testname}; $hit = 0; ($data_count, undef, $hit) = subtract_counts($data_count, $base_count); # Check whether this test case did hit any line at all if ($hit > 0) { # Write back resulting hash $data_testdata->{$testname} = $data_count; } else { # Delete test case which did not impact this # file delete($data_testdata->{$testname}); } # Add counts to sum of counts ($sumcount, $found, $hit) = add_counts($sumcount, $data_count); } # Write back resulting entry set_info_entry($data, $data_testdata, $sumcount, $data_funcdata, $data_checkdata, $found, $hit); $data_hash{$filename} = $data; } return (\%data_hash); } # # remove_unused_descriptions() # # Removes all test descriptions from the global hash %test_description which # are not present in %info_data. # sub remove_unused_descriptions() { my $filename; # The current filename my %test_list; # Hash containing found test names my $test_data; # Reference to hash test_name -> count_data my $before; # Initial number of descriptions my $after; # Remaining number of descriptions $before = scalar(keys(%test_description)); foreach $filename (keys(%info_data)) { ($test_data) = get_info_entry($info_data{$filename}); foreach (keys(%{$test_data})) { $test_list{$_} = ""; } } # Remove descriptions for tests which are not in our list foreach (keys(%test_description)) { if (!defined($test_list{$_})) { delete($test_description{$_}); } } $after = scalar(keys(%test_description)); if ($after < $before) { info("Removed ".($before - $after). " unused descriptions, $after remaining.\n"); } } # # merge_checksums(ref1, ref2, filename) # # REF1 and REF2 are references to hashes containing a mapping # # line number -> checksum # # Merge checksum lists defined in REF1 and REF2 and return reference to # resulting hash. Die if a checksum for a line is defined in both hashes # but does not match. # sub merge_checksums($$$) { my $ref1 = $_[0]; my $ref2 = $_[1]; my $filename = $_[2]; my %result; my $line; foreach $line (keys(%{$ref1})) { if (defined($ref2->{$line}) && ($ref1->{$line} ne $ref2->{$line})) { die("ERROR: checksum mismatch at $filename:$line\n"); } $result{$line} = $ref1->{$line}; } foreach $line (keys(%{$ref2})) { $result{$line} = $ref2->{$line}; } return \%result; } # # combine_info_entries(entry_ref1, entry_ref2, filename) # # Combine .info data entry hashes referenced by ENTRY_REF1 and ENTRY_REF2. # Return reference to resulting hash. # sub combine_info_entries($$$) { my $entry1 = $_[0]; # Reference to hash containing first entry my $testdata1; my $sumcount1; my $funcdata1; my $checkdata1; my $entry2 = $_[1]; # Reference to hash containing second entry my $testdata2; my $sumcount2; my $funcdata2; my $checkdata2; my %result; # Hash containing combined entry my %result_testdata; my $result_sumcount = {}; my %result_funcdata; my $lines_found; my $lines_hit; my $testname; my $filename = $_[2]; # Retrieve data ($testdata1, $sumcount1, $funcdata1, $checkdata1) = get_info_entry($entry1); ($testdata2, $sumcount2, $funcdata2, $checkdata2) = get_info_entry($entry2); # Merge checksums $checkdata1 = merge_checksums($checkdata1, $checkdata2, $filename); # Combine funcdata foreach (keys(%{$funcdata1})) { $result_funcdata{$_} = $funcdata1->{$_}; } foreach (keys(%{$funcdata2})) { $result_funcdata{$_} = $funcdata2->{$_}; } # Combine testdata foreach $testname (keys(%{$testdata1})) { if (defined($testdata2->{$testname})) { # testname is present in both entries, requires # combination ($result_testdata{$testname}) = add_counts($testdata1->{$testname}, $testdata2->{$testname}); } else { # testname only present in entry1, add to result $result_testdata{$testname} = $testdata1->{$testname}; } # update sum count hash ($result_sumcount, $lines_found, $lines_hit) = add_counts($result_sumcount, $result_testdata{$testname}); } foreach $testname (keys(%{$testdata2})) { # Skip testnames already covered by previous iteration if (defined($testdata1->{$testname})) { next; } # testname only present in entry2, add to result hash $result_testdata{$testname} = $testdata2->{$testname}; # update sum count hash ($result_sumcount, $lines_found, $lines_hit) = add_counts($result_sumcount, $result_testdata{$testname}); } # Calculate resulting sumcount # Store result set_info_entry(\%result, \%result_testdata, $result_sumcount, \%result_funcdata, $checkdata1, $lines_found, $lines_hit); return(\%result); } # # combine_info_files(info_ref1, info_ref2) # # Combine .info data in hashes referenced by INFO_REF1 and INFO_REF2. Return # reference to resulting hash. # sub combine_info_files($$) { my %hash1 = %{$_[0]}; my %hash2 = %{$_[1]}; my $filename; foreach $filename (keys(%hash2)) { if ($hash1{$filename}) { # Entry already exists in hash1, combine them $hash1{$filename} = combine_info_entries($hash1{$filename}, $hash2{$filename}, $filename); } else { # Entry is unique in both hashes, simply add to # resulting hash $hash1{$filename} = $hash2{$filename}; } } return(\%hash1); } # # apply_prefix(filename, prefix) # # If FILENAME begins with PREFIX, remove PREFIX from FILENAME and return # resulting string, otherwise return FILENAME. # sub apply_prefix($$) { my $filename = $_[0]; my $prefix = $_[1]; if (defined($prefix) && ($prefix ne "")) { if ($filename =~ /^\Q$prefix\E\/(.*)$/) { return substr($filename, length($prefix) + 1); } } return $filename; } # # system_no_output(mode, parameters) # # Call an external program using PARAMETERS while suppressing depending on # the value of MODE: # # MODE & 1: suppress STDOUT # MODE & 2: suppress STDERR # # Return 0 on success, non-zero otherwise. # sub system_no_output($@) { my $mode = shift; my $result; local *OLD_STDERR; local *OLD_STDOUT; # Save old stdout and stderr handles ($mode & 1) && open(OLD_STDOUT, ">>&STDOUT"); ($mode & 2) && open(OLD_STDERR, ">>&STDERR"); # Redirect to /dev/null ($mode & 1) && open(STDOUT, ">/dev/null"); ($mode & 2) && open(STDERR, ">/dev/null"); system(@_); $result = $?; # Close redirected handles ($mode & 1) && close(STDOUT); ($mode & 2) && close(STDERR); # Restore old handles ($mode & 1) && open(STDOUT, ">>&OLD_STDOUT"); ($mode & 2) && open(STDERR, ">>&OLD_STDERR"); return $result; } # # read_config(filename) # # Read configuration file FILENAME and return a reference to a hash containing # all valid key=value pairs found. # sub read_config($) { my $filename = $_[0]; my %result; my $key; my $value; local *HANDLE; if (!open(HANDLE, "<$filename")) { warn("WARNING: cannot read configuration file $filename\n"); return undef; } while () { chomp; # Skip comments s/#.*//; # Remove leading blanks s/^\s+//; # Remove trailing blanks s/\s+$//; next unless length; ($key, $value) = split(/\s*=\s*/, $_, 2); if (defined($key) && defined($value)) { $result{$key} = $value; } else { warn("WARNING: malformed statement in line $. ". "of configuration file $filename\n"); } } close(HANDLE); return \%result; } # # apply_config(REF) # # REF is a reference to a hash containing the following mapping: # # key_string => var_ref # # where KEY_STRING is a keyword and VAR_REF is a reference to an associated # variable. If the global configuration hash CONFIG contains a value for # keyword KEY_STRING, VAR_REF will be assigned the value for that keyword. # sub apply_config($) { my $ref = $_[0]; foreach (keys(%{$ref})) { if (defined($config->{$_})) { ${$ref->{$_}} = $config->{$_}; } } } # # get_html_prolog(FILENAME) # # If FILENAME is defined, return contents of file. Otherwise return default # HTML prolog. Die on error. # sub get_html_prolog($) { my $filename = $_[0]; my $result = ""; if (defined($filename)) { local *HANDLE; open(HANDLE, "<".$filename) or die("ERROR: cannot open html prolog $filename!\n"); while () { $result .= $_; } close(HANDLE); } else { $result = < \@pagetitle\@ END_OF_HTML ; } return $result; } # # get_html_epilog(FILENAME) # # If FILENAME is defined, return contents of file. Otherwise return default # HTML epilog. Die on error. # sub get_html_epilog($) { my $filename = $_[0]; my $result = ""; if (defined($filename)) { local *HANDLE; open(HANDLE, "<".$filename) or die("ERROR: cannot open html epilog $filename!\n"); while () { $result .= $_; } close(HANDLE); } else { $result = < END_OF_HTML ; } return $result; } mm3d-master/src/tests/libmm3d/glmath_test.cc000066400000000000000000001273131324021725400213200ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests glmath.h #include #include #include #include #include #include "glmath.h" #include "log.h" #include "test_common.h" double TOLERANCE = 0.001; class GlmathTest : public QObject { Q_OBJECT private slots: void initTestCase() { log_enable_debug( false ); } void testVectorInit() { { Vector v; QVERIFY_TRUE( fabs(v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(1.0 - v.get(3)) < TOLERANCE ); } { // 4th element is ignored double array[4] = { 3, 4, 5, 6 }; Vector v(array); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(1.0 - v.get(3)) < TOLERANCE ); } { // 4th element defaults to 1 Vector v(3, 4, 5); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(1.0 - v.get(3)) < TOLERANCE ); } { Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); } } void testVectorSetGet() { { Vector v; QVERIFY_TRUE( fabs(v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(1 - v.get(3)) < TOLERANCE ); } { Vector v; v.set(0, 3); v.set(1, 4); v.set(2, 5); v.set(3, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); } { Vector v; v[0] = 3; v[1] = 4; v[2] = 5; v[3] = 6; QVERIFY_TRUE( fabs(3 - v[0]) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v[1]) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v[2]) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v[3]) < TOLERANCE ); } { const Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); } { const Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v[0]) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v[1]) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v[2]) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v[3]) < TOLERANCE ); } } void testVectorGetVector() { { const Vector vec(3, 4, 5, 6); const double * v = vec.getVector(); QVERIFY_TRUE( fabs(3 - v[0]) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v[1]) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v[2]) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v[3]) < TOLERANCE ); } { Vector vec(3, 4, 5, 6); double * v = vec.getVector(); QVERIFY_TRUE( fabs(3 - v[0]) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v[1]) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v[2]) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v[3]) < TOLERANCE ); v[1] = 7.0; QVERIFY_TRUE( fabs(3 - vec[0]) < TOLERANCE ); QVERIFY_TRUE( fabs(7 - vec[1]) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - vec[2]) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - vec[3]) < TOLERANCE ); } } void testVectorSetAll() { { // 4th element defaults to 1 Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); v.setAll( 7, 8, 9 ); QVERIFY_TRUE( fabs(7 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(8 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(9 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(1 - v.get(3)) < TOLERANCE ); } { Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); v.setAll( 7, 8, 9, 10 ); QVERIFY_TRUE( fabs(7 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(8 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(9 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(10 - v.get(3)) < TOLERANCE ); } { // 4th element defaults to 1 Vector v(3, 4, 5, 6); QVERIFY_TRUE( fabs(3 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(5 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(3)) < TOLERANCE ); double v1[4] = { 7, 8, 9, 10 }; v.setAll( v1, 4 ); QVERIFY_TRUE( fabs(7 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(8 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(9 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(10 - v.get(3)) < TOLERANCE ); // Don't set v[3] double v2[4] = { 2, 4, 6, 8 }; v.setAll( v2, 3 ); QVERIFY_TRUE( fabs(2 - v.get(0)) < TOLERANCE ); QVERIFY_TRUE( fabs(4 - v.get(1)) < TOLERANCE ); QVERIFY_TRUE( fabs(6 - v.get(2)) < TOLERANCE ); QVERIFY_TRUE( fabs(10 - v.get(3)) < TOLERANCE ); } } void testVectorEqual() { { const Vector vec( 1, 2, 3, 4 ); const Vector exp( 1, 2, 3, 4 ); QVERIFY_TRUE(exp == vec); } { const Vector vec( 1, 2, 3, 4 ); const Vector exp( 1.001, 2, 3, 4 ); QVERIFY_FALSE(exp == vec); } { const Vector vec( 1, 2, 3, 4 ); const Vector exp( 1, 2.001, 3, 4 ); QVERIFY_FALSE(exp == vec); } { const Vector vec( 1, 2, 3, 4 ); const Vector exp( 1, 2, 3.001, 4 ); QVERIFY_FALSE(exp == vec); } { const Vector vec( 1, 2, 3, 4 ); const Vector exp( 1, 2, 3, 4.001 ); QVERIFY_FALSE(exp == vec); } } void testVectorScale() { { Vector v(3, 4, 5, 6); const Vector exp(-6, -8, -10, -12); v.scale( -2 ); QVERIFY_TRUE( v == exp ); } { Vector v(3, 4, 5, 6); const Vector exp(-6, -8, -10, 6); v.scale3( -2 ); QVERIFY_TRUE( v == exp ); } { const Vector v(3, 4, 5, 6); const Vector exp(-6, -8, -10, -12); const Vector res = v * -2.0; QVERIFY_TRUE( res == exp ); } } void testVectorPlusEquals() { { Vector lhs(1, 2, 3, 4); const Vector rhs(3, 4, 5, 6); const Vector exp(4, 6, 8, 10); lhs += rhs; QVERIFY_TRUE( lhs == exp ); } { Vector lhs(1, 2, 3, 4); const Vector exp(2, 4, 6, 8); lhs += lhs; QVERIFY_TRUE( lhs == exp ); } { const Vector lhs(1, 2, 3, 4); const Vector rhs(3, 4, 5, 6); const Vector exp(4, 6, 8, 10); const Vector res = lhs + rhs; QVERIFY_TRUE( res == exp ); } } void testVectorMinusEquals() { { Vector lhs(1, 2, 3, 4); const Vector rhs(2, 4, 6, 8); const Vector exp(-1, -2, -3, -4); lhs -= rhs; QVERIFY_TRUE( lhs == exp ); } { Vector lhs(1, 2, 3, 4); const Vector exp(0, 0, 0, 0); lhs -= lhs; QVERIFY_TRUE( lhs == exp ); } { const Vector lhs(1, 2, 3, 4); const Vector rhs(2, 4, 6, 8); const Vector exp(-1, -2, -3, -4); const Vector res = lhs - rhs; QVERIFY_TRUE( res == exp ); } } void testVectorMag() { { const Vector x(1, 0, 0, 1); const Vector y(0, 2, 0, 1); const Vector z(0, 0, 3, 1); QVERIFY_TRUE( fabs(x.mag3() - 1) < TOLERANCE ); QVERIFY_TRUE( fabs(y.mag3() - 2) < TOLERANCE ); QVERIFY_TRUE( fabs(z.mag3() - 3) < TOLERANCE ); } { const Vector x(1, 0, 0, 0); const Vector y(0, 2, 0, 0); const Vector z(0, 0, 3, 0); const Vector w(0, 0, 0, 4); QVERIFY_TRUE( fabs(x.mag() - 1) < TOLERANCE ); QVERIFY_TRUE( fabs(y.mag() - 2) < TOLERANCE ); QVERIFY_TRUE( fabs(z.mag() - 3) < TOLERANCE ); QVERIFY_TRUE( fabs(w.mag() - 4) < TOLERANCE ); } { const Vector v(1, -2, 3, -4); QVERIFY_TRUE( fabs(v.mag3() - 3.741657) < TOLERANCE ); QVERIFY_TRUE( fabs(v.mag() - 5.477226) < TOLERANCE ); } } void testVectorDot() { { const Vector lhs(1, 0, 0, 1); const Vector rhs(1, 0, 0, 1); QVERIFY_TRUE( fabs(lhs.dot3(rhs) - 1 ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(0, 1, 0, 1); QVERIFY_TRUE( fabs(lhs.dot3(rhs) ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(-1, 0, 0, 1); QVERIFY_TRUE( fabs(lhs.dot3(rhs) + 1 ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(0, -1, 0, 1); QVERIFY_TRUE( fabs(lhs.dot3(rhs) ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); Vector rhs(1, -1, 0, 1); rhs.normalize3(); QVERIFY_TRUE( fabs(lhs.dot3(rhs) - cos(PI / 4)) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); Vector rhs(-1, -1, 0, 1); rhs.normalize3(); QVERIFY_TRUE( fabs(lhs.dot3(rhs) - cos(PI * 3 / 4)) < TOLERANCE ); } } void testVectorNormalize() { { Vector vec(1, 2, 3, 4); Vector exp(0.267261, 0.534522, 0.801784, 4); vec.normalize3(); QVERIFY_TRUE( vec == exp ); } { Vector vec(1, 2, 3, 4); Vector exp(0.182574, 0.365148, 0.547723, 0.730297); vec.normalize(); QVERIFY_TRUE( vec == exp ); } } void testVectorCross() { // FIXME could be more thorough { const Vector lhs(1, 0, 0, 1); const Vector rhs(0, 1, 0, 1); const Vector exp(0, 0, 1, 1); const Vector res = lhs.cross3(rhs); QVERIFY_TRUE( res == exp ); } { const Vector lhs(0, 1, 0, 1); const Vector rhs(1, 0, 0, 1); const Vector exp(0, 0, -1, 1); const Vector res = lhs.cross3(rhs); QVERIFY_TRUE( res == exp ); } } void testVectorTranslate() { // FIXME this is not translation, this is transformation. // 1) Make this actually a translation. // 2) Change Vector::translate calls that should be transform // call Vector::transform instead. { Matrix mat; Vector vec(1, 1, 1); const Vector exp(5, 6, 7, 1); mat.setTranslation( 4, 5, 6 ); vec.translate( mat ); QVERIFY_TRUE( vec == exp ); } } void testVectorTransform() { // Translate { Matrix mat; Vector vec(1, 1, 1); Vector exp(5, 6, 7); mat.setTranslation( 4, 5, 6 ); vec.transform( mat ); QVERIFY_TRUE( vec == exp ); } // Translate (ignored, transform3) { Matrix mat; Vector vec(1, 1, 1); Vector exp(1, 1, 1); mat.setTranslation( 4, 5, 6 ); vec.transform3( mat ); QVERIFY_TRUE( vec == exp ); } // X Rotation { Matrix mat; Vector vec(1, 2, 3); Vector exp(1, -3, 2); mat.setRotation( Vector(PI / 2, 0, 0) ); vec.transform( mat ); QVERIFY_TRUE( vec == exp ); } // Y Rotation { Matrix mat; Vector vec(1, 2, 3); Vector exp(-3, 2, 1); mat.setRotation( Vector(0, -PI / 2, 0) ); vec.transform( mat ); QVERIFY_TRUE( vec == exp ); } // Z Rotation { Matrix mat; Vector vec(1, 2, 3); Vector exp(2, -1, 3); mat.setRotation( Vector(0, 0, PI*3 / 2) ); vec.transform( mat ); QVERIFY_TRUE( vec == exp ); } // Scale { Matrix mat; Vector vec(1, 2, 3); Vector exp(2, 6, 12, 5); mat.set( 0, 0, 2.0 ); mat.set( 1, 1, 3.0 ); mat.set( 2, 2, 4.0 ); mat.set( 3, 3, 5.0 ); vec.transform( mat ); QVERIFY_TRUE( vec == exp ); } // Scale3 { Matrix mat; Vector vec(1, 2, 3); Vector exp(2, 6, 12); mat.set( 0, 0, 2.0 ); mat.set( 1, 1, 3.0 ); mat.set( 2, 2, 4.0 ); mat.set( 3, 3, 5.0 ); vec.transform3( mat ); QVERIFY_TRUE( vec == exp ); } // Scale { Matrix mat; const Vector vec(1, 2, 3); const Vector exp(2, 6, 12, 5); mat.set( 0, 0, 2.0 ); mat.set( 1, 1, 3.0 ); mat.set( 2, 2, 4.0 ); mat.set( 3, 3, 5.0 ); const Vector res = vec * mat; QVERIFY_TRUE( res == exp ); } } void testMatrixInit() { const Matrix m; for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { if ( r == c ) { QVERIFY_TRUE(float_equiv(m.get(r, c), 1.0)); } else { QVERIFY_TRUE(float_equiv(m.get(r, c), 0.0)); } } } } void testMatrixLoadIdentity() { Matrix m; QVERIFY_TRUE( m.isIdentity() ); for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { m.set(r, c, 4.0); QVERIFY_TRUE(float_equiv(m.get(r, c), 4.0)); } } QVERIFY_FALSE( m.isIdentity() ); m.loadIdentity(); QVERIFY_TRUE( m.isIdentity() ); for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { if ( r == c ) { QVERIFY_TRUE(float_equiv(m.get(r, c), 1.0)); } else { QVERIFY_TRUE(float_equiv(m.get(r, c), 0.0)); } } } } void testMatrixSetGet() { Matrix m; QVERIFY_TRUE( m.isIdentity() ); for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { m.set(r, c, r * 8.0 + c); } } for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { QVERIFY_TRUE(float_equiv(m.get(r, c), r * 8.0 + c)); } } } void testMatrixEqual() { for ( int c = 0; c < 4; ++c ) { for ( int r = 0; r < 4; ++r ) { Matrix lhs; Matrix rhs; QVERIFY_TRUE(lhs == rhs); QVERIFY_TRUE(lhs.equiv(rhs)); lhs.set(r, c, lhs.get(r, c) + 0.001); QVERIFY_FALSE(lhs == rhs); QVERIFY_FALSE(lhs.equiv(rhs)); } } } void testMatrixEquiv() { { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(-PI, 0, 0) ); rhs.setRotation( Vector(PI, 0, 0) ); QVERIFY_TRUE(lhs.equiv(rhs)); } { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(-PI / 2.0, 0, 0) ); rhs.setRotation( Vector(PI / 2.0, 0, 0) ); QVERIFY_FALSE(lhs.equiv(rhs)); } { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(0, -PI, 0) ); rhs.setRotation( Vector(0, PI, 0) ); QVERIFY_TRUE(lhs.equiv(rhs)); } { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(0, -PI / 2.0, 0) ); rhs.setRotation( Vector(0, PI / 2.0, 0) ); QVERIFY_FALSE(lhs.equiv(rhs)); } { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(0, 0, -PI) ); rhs.setRotation( Vector(0, 0, PI) ); QVERIFY_TRUE(lhs.equiv(rhs)); } { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(0, 0, -PI / 2.0) ); rhs.setRotation( Vector(0, 0, PI / 2.0) ); QVERIFY_FALSE(lhs.equiv(rhs)); } } void testMatrixSetGetTranslation() { { Matrix m; m.setTranslation( 1, 2, 3 ); double x = 0, y = 0, z = 0; m.getTranslation( x, y, z ); QVERIFY_TRUE(float_equiv(x, 1.0)); QVERIFY_TRUE(float_equiv(y, 2.0)); QVERIFY_TRUE(float_equiv(z, 3.0)); } { Matrix m; m.setTranslation( Vector(4, 6, 8) ); Vector v; m.getTranslation( v ); QVERIFY_TRUE(float_equiv(v[0], 4.0)); QVERIFY_TRUE(float_equiv(v[1], 6.0)); QVERIFY_TRUE(float_equiv(v[2], 8.0)); } { Matrix m; double array[3] = { 1, 4, 9 }; m.setTranslation( array ); double v[3] = { 0, 0, 0 }; m.getTranslation( v ); QVERIFY_TRUE(float_equiv(v[0], 1.0)); QVERIFY_TRUE(float_equiv(v[1], 4.0)); QVERIFY_TRUE(float_equiv(v[2], 9.0)); } } void testMatrixSetGetRotation() { { Matrix m; m.setRotation( Vector(PI/2, PI/3, PI/4) ); Vector v; m.getRotation( v ); QVERIFY_TRUE(float_equiv(v[0], PI/2)); QVERIFY_TRUE(float_equiv(v[1], PI/3)); QVERIFY_TRUE(float_equiv(v[2], PI/4)); double x = 0, y = 0, z = 0; m.getRotation( x, y, z ); QVERIFY_TRUE(float_equiv(x, PI/2)); QVERIFY_TRUE(float_equiv(y, PI/3)); QVERIFY_TRUE(float_equiv(z, PI/4)); } { Matrix m; double vec[3] = { PI/3, PI/4, PI/5 }; m.setRotation( vec ); double v[3] = { 0, 0, 0 }; m.getRotation( v ); QVERIFY_TRUE(float_equiv(v[0], PI/3)); QVERIFY_TRUE(float_equiv(v[1], PI/4)); QVERIFY_TRUE(float_equiv(v[2], PI/5)); } } void testMatrixApplyRotation() { { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); Vector vec(0, 2, 0); const Vector exp(0, 0, 2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); double vec[4] = { 0, 2, 0, 1 }; const Vector exp(0, 0, 2); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); float vec[4] = { 0, 2, 0, 1 }; const Vector exp(0, 0, 2); m.apply( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply with a 0 'w' element in the vector { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); Vector vec(0, 2, 0, 0); const Vector exp(0, 0, 2, 0); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); double vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2, 0); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); float vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2, 0); m.apply( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply3 { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); Vector vec(0, 2, 0, 0); const Vector exp(0, 0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); double vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); float vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply3x { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); Vector vec(0, 2, 0, 0); const Vector exp(0, 0, 2, 0); m.apply3x( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); double vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2); m.apply3x( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setRotation( Vector(PI/2, 0, 0) ); float vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 0, 2); m.apply3x( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } } void testMatrixApplyTranslation() { { Matrix m; m.setTranslation( Vector(1, 2, 3) ); Vector vec(0, 2, 0); const Vector exp(1, 4, 3); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); double vec[4] = { 0, 2, 0, 1 }; const Vector exp(1, 4, 3); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); float vec[4] = { 0, 2, 0, 1 }; const Vector exp(1, 4, 3); m.apply( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply with a 0 'w' element in the vector { Matrix m; m.setTranslation( Vector(1, 2, 3) ); Vector vec(0, 2, 0, 0); const Vector exp(0, 2, 0, 0); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); double vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 2, 0, 0); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); float vec[4] = { 0, 2, 0, 0 }; const Vector exp(0, 2, 0, 0); m.apply( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply3 { Matrix m; m.setTranslation( Vector(1, 2, 3) ); Vector vec(0, 2, 0); const Vector exp(0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); double vec[4] = { 0, 2, 0, 1 }; const Vector exp(0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); float vec[4] = { 0, 2, 0, 1 }; const Vector exp(0, 2, 0); m.apply3( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } // Apply3x { Matrix m; m.setTranslation( Vector(1, 2, 3, 0) ); Vector vec(0, 2, 0, 0); const Vector exp(1, 4, 3, 0); m.apply3x( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); double vec[4] = { 0, 2, 0, 0 }; const Vector exp(1, 4, 3); m.apply3x( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { Matrix m; m.setTranslation( Vector(1, 2, 3) ); float vec[4] = { 0, 2, 0, 0 }; const Vector exp(1, 4, 3); m.apply3x( vec ); QVERIFY_TRUE(float_equiv((float)exp[0], vec[0])); QVERIFY_TRUE(float_equiv((float)exp[1], vec[1])); QVERIFY_TRUE(float_equiv((float)exp[2], vec[2])); } } void testMatrixApplyScale() { { Matrix m; m.set(0, 0, 2); m.set(1, 1, -4); m.set(2, 2, 6); Vector vec(2, 2, 2); const Vector exp(4, -8, 12); m.apply( vec ); QVERIFY_TRUE(exp == vec); } // Apply with a 0 'w' element in the vector { Matrix m; m.set(0, 0, 2); m.set(1, 1, -4); m.set(2, 2, 6); Vector vec(2, 2, 2, 0); const Vector exp(4, -8, 12, 0); m.apply( vec ); QVERIFY_TRUE(exp == vec); } // Apply3 { Matrix m; m.set(0, 0, 2); m.set(1, 1, -4); m.set(2, 2, 6); Vector vec(2, 2, 2, 0); const Vector exp(4, -8, 12, 0); m.apply3( vec ); QVERIFY_TRUE(exp == vec); } // Apply3x { Matrix m; m.set(0, 0, 2); m.set(1, 1, -4); m.set(2, 2, 6); Vector vec(2, 2, 2, 0); const Vector exp(4, -8, 12, 0); m.apply3( vec ); QVERIFY_TRUE(exp == vec); } } void testMatrixApplyRotationTranslation() { Matrix m; m.setTranslation( Vector(1, 2, 3) ); m.setRotation( Vector(0, -PI/2, 0) ); { double vec[4] = { 2, 0, 0, 1 }; const Vector exp(1, 2, 5); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { double vec[4] = { 2, 0, 0, 0 }; const Vector exp(0, 0, 2, 0); m.apply( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { double vec[4] = { 2, 0, 0, 0 }; const Vector exp(1, 2, 5, 0); m.apply3x( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { double vec[4] = { 2, 0, 0, 1 }; const Vector exp(0, 0, 2); m.apply3( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } } void testMatrixApplyInverse() { Matrix m; m.setTranslation( Vector(1, 2, 3) ); m.setRotation( Vector(0, -PI/2, 0) ); { // Inverse rotate doesn't apply translation double vec[4] = { 2, 0, 0, 1 }; const Vector exp(0, 0, -2); m.inverseRotateVector( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } { // Inverse translate doesn't apply rotation double vec[4] = { 2, 0, 0, 1 }; const Vector exp(1, -2, -3); m.inverseTranslateVector( vec ); QVERIFY_TRUE(float_equiv(exp[0], vec[0])); QVERIFY_TRUE(float_equiv(exp[1], vec[1])); QVERIFY_TRUE(float_equiv(exp[2], vec[2])); } } void testMatrixSetInverseRotation() { Matrix m; m.setInverseRotation( Vector(0, -PI/2, 0).getVector() ); Vector vec(2, 0, 0); Vector exp(0, 0, -2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } void testMatrixSetInverseInDegrees() { Matrix m; m.setInverseRotationInDegrees( Vector(0, -90, 0).getVector() ); Vector vec(2, 0, 0); Vector exp(0, 0, -2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } void testMatrixSetRotationInDegrees() { { Matrix m; m.setRotationInDegrees( Vector(0, 90, 0) ); Vector vec(2, 0, 0); Vector exp(0, 0, -2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; double rot[3] = { 0, 90, 0 }; m.setRotationInDegrees( rot ); Vector vec(2, 0, 0); Vector exp(0, 0, -2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } { Matrix m; double rot[3] = { 0, 90, 0 }; m.setRotationInDegrees( rot[0], rot[1], rot[2] ); Vector vec(2, 0, 0); Vector exp(0, 0, -2); m.apply( vec ); QVERIFY_TRUE(exp == vec); } } void testMatrixSetGetQuaternion() { { Matrix m; m.setRotationOnAxis( Vector(1, 0, 0).getVector(), PI/2 ); Vector exp(PI/2, 0, 0); Vector rot(0, 0, 0); m.getRotation(rot.getVector()); QVERIFY_TRUE(exp == rot); Quaternion qexp; qexp.setRotationOnAxis(1, 0, 0, PI/2); Quaternion quat; m.getRotationQuaternion(quat); QVERIFY_TRUE(qexp == quat); } { Matrix m; Quaternion q; q.setRotationOnAxis( 0, 1, 0, PI/2 ); m.setRotationQuaternion( q ); Vector exp(0, PI/2, 0); Vector rot(0, 0, 0); m.getRotation(rot.getVector()); QVERIFY_TRUE(exp == rot); Quaternion qexp; qexp.setRotationOnAxis(0, 1, 0, PI/2); Quaternion quat; m.getRotationQuaternion(quat); QVERIFY_TRUE(qexp == quat); } } void testMatrixQuaternionRotation() { Vector v(1, 0, 1); v.normalize3(); Matrix m; m.setRotationOnAxis( v.getVector(), PI/2 ); Vector v1(2, 0, 0); Vector v2(0, 0, 2); Vector exp1(1, sqrt(2), 1); Vector exp2(1, -sqrt(2), 1); m.apply(v1); m.apply(v2); QVERIFY_TRUE( exp1 == v1 ); QVERIFY_TRUE( exp2 == v2 ); } void testMatrixMultiply() { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(PI/2, 0.0, 0.0) ); rhs.setRotation( Vector(0.0, PI/2, 0.0) ); { // 0 0 -1 0 // 1 0 0 0 // 0 -1 0 0 // 0 0 0 1 Matrix exp; exp.set(0, 0, 0); exp.set(1, 1, 0); exp.set(2, 2, 0); exp.set(0, 2, -1); exp.set(1, 0, 1); exp.set(2, 1, -1); Matrix res = lhs * rhs; QVERIFY_TRUE(exp == res); } { // 0 1 0 0 // 0 0 1 0 // 1 0 0 0 // 0 0 0 1 Matrix exp; exp.set(0, 0, 0); exp.set(1, 1, 0); exp.set(2, 2, 0); exp.set(0, 1, 1); exp.set(1, 2, 1); exp.set(2, 0, 1); Matrix res = rhs * lhs; QVERIFY_TRUE(exp == res); } { // post multiply: lhs = rhs * lhs // 0 1 0 0 // 0 0 1 0 // 1 0 0 0 // 0 0 0 1 Matrix exp; exp.set(0, 0, 0); exp.set(1, 1, 0); exp.set(2, 2, 0); exp.set(0, 1, 1); exp.set(1, 2, 1); exp.set(2, 0, 1); Matrix res = lhs; res.postMultiply(rhs); QVERIFY_TRUE(exp == res); } } void testMatrixNormalizeRotation() { Matrix lhs; Matrix rhs; lhs.setRotation( Vector(PI/2, PI, -PI/2) ); rhs.set( 0, 0, 2 ); rhs.set( 1, 1, 3 ); rhs.set( 2, 2, 4 ); Matrix m = rhs * lhs; { Vector vec( 1, 2, 3 ); m.apply( vec ); Vector exp(-12, 2, -6); QVERIFY_TRUE( exp == vec ); } m.normalizeRotation(); { Vector vec( 1, 2, 3 ); m.apply( vec ); Vector exp( -3, 1, -2 ); QVERIFY_TRUE( exp == vec ); } } void testMatrixGetInverse() { { Matrix m; m.setRotation( Vector( PI/2, 0, 0 ) ); Matrix inv = m.getInverse(); Matrix id = m * inv; QVERIFY_TRUE( id.isIdentity() ); QVERIFY_TRUE( fabs(m.getDeterminant()) > TOLERANCE ); } { Matrix m; m.setTranslation( 1, 2, 3 ); Matrix inv = m.getInverse(); Matrix id = m * inv; QVERIFY_TRUE( id.isIdentity() ); QVERIFY_TRUE( fabs(m.getDeterminant()) > TOLERANCE ); } { Matrix m; m.set( 0, 0, 2 ); m.set( 1, 1, 3 ); m.set( 2, 2, 4 ); Matrix inv = m.getInverse(); Matrix id = m * inv; QVERIFY_TRUE( id.isIdentity() ); QVERIFY_TRUE( fabs(m.getDeterminant()) > TOLERANCE ); } { // Can't invert Matrix m; m.set( 0, 0, 2 ); m.set( 1, 1, 0 ); m.set( 2, 2, 4 ); Matrix inv = m.getInverse(); Matrix id = m * inv; QVERIFY_FALSE( id.isIdentity() ); QVERIFY_FALSE( fabs(m.getDeterminant()) > TOLERANCE ); } } void testQuaternionInit() { { const Quaternion q; const Vector exp( 0, 0, 0, 1 ); QVERIFY_TRUE( exp == q ); } { const Quaternion q( Vector(1, 2, 3, 4).getVector() ); const Vector exp( 1, 2, 3, 4 ); QVERIFY_TRUE( exp == q ); } { const Quaternion q( Vector(1, 2, 3, 4) ); const Vector exp( 1, 2, 3, 4 ); QVERIFY_TRUE( exp == q ); } } void testQuaternionSet() { Quaternion q; { const Vector exp( 0, 0, 0, 1 ); QVERIFY_TRUE( exp == q ); } q.set(0, 1); q.set(1, 2); q.set(2, 3); q.set(3, 4); { const Vector exp( 1, 2, 3, 4 ); QVERIFY_TRUE( exp == q ); } QVERIFY_TRUE( float_equiv( 1.0, q.get(0) ) ); QVERIFY_TRUE( float_equiv( 2.0, q.get(1) ) ); QVERIFY_TRUE( float_equiv( 3.0, q.get(2) ) ); QVERIFY_TRUE( float_equiv( 4.0, q.get(3) ) ); const double * vec = q.getVector(); QVERIFY_TRUE( float_equiv( 1.0, vec[0] ) ); QVERIFY_TRUE( float_equiv( 2.0, vec[1] ) ); QVERIFY_TRUE( float_equiv( 3.0, vec[2] ) ); QVERIFY_TRUE( float_equiv( 4.0, vec[3] ) ); } // Note this function also tests Quaternion::getRotationOnAxis // Quaternion::setRotationOnAxis is tested in the Matrix code void testQuaternionEulerAngles() { { Quaternion q; q.setEulerAngles( Vector(PI/2, 0, 0).getVector() ); double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 1, 0, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } { Quaternion q; q.setEulerAngles( Vector(0, PI/2, 0).getVector() ); double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 0, 1, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } { Quaternion q; q.setEulerAngles( Vector(0, 0, PI/2).getVector() ); double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 0, 0, 1 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } } void testQuaternionSwapHandedness() { Quaternion q; q.setEulerAngles( Vector(PI/2, 0, 0).getVector() ); { double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 1, 0, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } q.swapHandedness(); { double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 1, 0, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } } void testQuaternionNormalize() { Quaternion q(Vector(1, 2, 3, 4).getVector()); q.normalize(); Vector exp(1, 2, 3, 4); exp.normalize(); QVERIFY_TRUE( exp == q ); } void testQuaternionSetRotationToPoint() { Vector face(0, 0, 2); Vector point(3, 0, 0); { Quaternion q; q.setRotationToPoint( face, point ); double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 0, 1, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } { Quaternion q; q.setRotationToPoint( face[0], face[1], face[2], point[0], point[1], point[2] ); double axis[3] = { 0, 0, 0 }; double rad = 0; q.getRotationOnAxis( axis, rad ); double exp[3] = { 0, 1, 0 }; QVERIFY_TRUE( floatCompareVector(axis, exp, 3) ); QVERIFY_TRUE( float_equiv(rad, PI/2) ); } } void testDistance() { // vector functions { Vector p1(2, 3, 4); Vector p2(4, 6, 8); QVERIFY_TRUE( float_equiv(5.385165, distance(p1, p2)) ); } { Vector p1(2, 3, 4); Vector p2(4, 6, 8); QVERIFY_TRUE( float_equiv(5.385165, distance(p1.getVector(), p2.getVector())) ); } // template functions { Vector p1(2, 3, 4); Vector p2(4, 6, 8); QVERIFY_TRUE( float_equiv(5.385165, distance( p1[0], p1[1], p1[2], p2[0], p2[1], p2[2] )) ); } { Vector p1(2, 3, 4); Vector p2(4, 6, 8); QVERIFY_TRUE( float_equiv(3.605551, distance( p1[0], p1[1], p2[0], p2[1] )) ); } } void testMag() { Vector vec(2, 3, 4); QVERIFY_TRUE( float_equiv(5.385165, mag3(vec.getVector())) ); } void testNormalize() { Vector vec(2, 3, 4, 5); normalize3( vec.getVector() ); Vector exp(0.371391, 0.557086, 0.742781, 5); QVERIFY_TRUE(exp == vec); } void testDot() { { const Vector lhs(1, 0, 0, 1); const Vector rhs(1, 0, 0, 1); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) - 1 ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(0, 1, 0, 1); QVERIFY_TRUE( fabs(lhs.dot3(rhs) ) < TOLERANCE ); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(-1, 0, 0, 1); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) + 1 ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); const Vector rhs(0, -1, 0, 1); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); Vector rhs(1, -1, 0, 1); rhs.normalize3(); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) - cos(PI / 4) ) < TOLERANCE ); } { const Vector lhs(1, 0, 0, 1); Vector rhs(-1, -1, 0, 1); rhs.normalize3(); QVERIFY_TRUE( fabs(dot3(lhs.getVector(), rhs.getVector()) - cos(PI * 3 / 4) ) < TOLERANCE ); } } void testEquiv() { { const Vector v1( 1, 1, 1 ); const Vector v2( 1, 1, 1 ); QVERIFY_TRUE( equiv3( v1.getVector(), v2.getVector() ) ); } { const Vector v1( 1, 1, 1 ); const Vector v2( 1.001, 1, 1 ); QVERIFY_FALSE( equiv3( v1.getVector(), v2.getVector() ) ); } { const Vector v1( 1, 1, 1 ); const Vector v2( 1, 1.001, 1 ); QVERIFY_FALSE( equiv3( v1.getVector(), v2.getVector() ) ); } { const Vector v1( 1, 1, 1 ); const Vector v2( 1, 1, 1.001 ); QVERIFY_FALSE( equiv3( v1.getVector(), v2.getVector() ) ); } } void testCalculateNormal() { // FIXME could be more thorough { const Vector p1(1, 1, 1, 1); const Vector p2(3, 1, 1, 1); const Vector p3(1, 4, 1, 1); const Vector exp(0, 0, 1, 1); Vector normal; calculate_normal( normal.getVector(), p1.getVector(), p2.getVector(), p3.getVector() ); QVERIFY_TRUE( normal == exp ); } { const Vector p1(1, 1, 1, 1); const Vector p2(1, 4, 1, 1); const Vector p3(3, 1, 1, 1); const Vector exp(0, 0, -1, 1); Vector normal; calculate_normal( normal.getVector(), p1.getVector(), p2.getVector(), p3.getVector() ); QVERIFY_TRUE( normal == exp ); } { const Vector lhs(0, 1, 0, 1); const Vector rhs(1, 0, 0, 1); const Vector exp(0, 0, -1, 1); const Vector res = lhs.cross3(rhs); QVERIFY_TRUE( res == exp ); } } // Doesn't actually test anything, but it's just for debugging anyway. void testShow() { Matrix m; m.show(); Vector v; v.show(); Quaternion q; q.show(); } }; QTEST_MAIN(GlmathTest) #include "glmath_test.moc" mm3d-master/src/tests/libmm3d/intfile.cc000066400000000000000000000013651324021725400204350ustar00rootroot00000000000000#include #include #include #include #include int main( int argc, char * argv[] ) { if ( argc != 3 ) { fprintf( stderr, "Usage: ./intfile filename dword_count\n" ); return -1; } const char * filename = argv[1]; size_t dword_count = atoi( argv[2] ); FILE * fp = fopen( filename, "w" ); if ( !fp ) { fprintf( stderr, "open %s: %s\n", filename, strerror(errno) ); return -1; } for ( size_t t = 0; t < dword_count; ++t ) { uint32_t val = t; if ( fwrite( &val, sizeof(val), 1, fp ) < 1 ) { fprintf( stderr, "write %s: %s\n", filename, strerror(errno) ); return -1; } } fclose( fp ); return 0; } mm3d-master/src/tests/libmm3d/little_endian_test.cc000066400000000000000000000135551324021725400226610ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests libmm3d/endianconfig.h as little endian #include #include "test_common.h" #include "config.h" #undef BYTEORDER #define BYTEORDER 1234 #include "endianconfig.h" class BigEndianTest : public QObject { Q_OBJECT private slots: void testLittle32() { uint8_t in[4] = { 0x01, 0x02, 0x03, 0x04 }; // little to host { uint32_t source = 0; memcpy( &source, in, sizeof(source) ); uint32_t host = ltoh_u32( source ); QVERIFY_EQ( 0, memcmp( &host, in, sizeof(host) ) ); } { int32_t source = 0; memcpy( &source, in, sizeof(source) ); int32_t host = ltoh_32( source ); QVERIFY_EQ( 0, memcmp( &host, in, sizeof(host) ) ); } // host to little { uint32_t host = 0; memcpy( &host, in, sizeof(host) ); uint32_t dest = htol_u32( host ); QVERIFY_EQ( 0, memcmp( &dest, in, sizeof(dest) ) ); } { int32_t host = 0; memcpy( &host, in, sizeof(host) ); int32_t dest = htol_32( host ); QVERIFY_EQ( 0, memcmp( &dest, in, sizeof(dest) ) ); } } void testLittle16() { uint8_t in[2] = { 0x01, 0x02 }; // little to host { uint16_t source = 0; memcpy( &source, in, sizeof(source) ); uint16_t host = ltoh_u16( source ); QVERIFY_EQ( 0, memcmp( &host, in, sizeof(host) ) ); } { int16_t source = 0; memcpy( &source, in, sizeof(source) ); int16_t host = ltoh_16( source ); QVERIFY_EQ( 0, memcmp( &host, in, sizeof(host) ) ); } // host to little { uint16_t host = 0; memcpy( &host, in, sizeof(host) ); uint16_t dest = htol_u16( host ); QVERIFY_EQ( 0, memcmp( &dest, in, sizeof(dest) ) ); } { int16_t host = 0; memcpy( &host, in, sizeof(host) ); int16_t dest = htol_16( host ); QVERIFY_EQ( 0, memcmp( &dest, in, sizeof(dest) ) ); } } void testLittleFloat() { uint8_t in[4] = { 0x01, 0x02, 0x03, 0x04 }; // little to host { float source = 0; memcpy( &source, in, sizeof(source) ); float host = ltoh_float( source ); QVERIFY_EQ( 0, memcmp( &host, in, sizeof(host) ) ); } // host to little { float host = 0; memcpy( &host, in, sizeof(host) ); float dest = htol_float( host ); QVERIFY_EQ( 0, memcmp( &dest, in, sizeof(dest) ) ); } } void testBig32() { uint8_t in[4] = { 0x01, 0x02, 0x03, 0x04 }; uint8_t out[4] = { 0x04, 0x03, 0x02, 0x01 }; // big to host { uint32_t source = 0; memcpy( &source, in, sizeof(source) ); uint32_t host = btoh_u32( source ); QVERIFY_EQ( 0, memcmp( &host, out, sizeof(host) ) ); } { int32_t source = 0; memcpy( &source, in, sizeof(source) ); int32_t host = btoh_32( source ); QVERIFY_EQ( 0, memcmp( &host, out, sizeof(host) ) ); } // host to big { uint32_t host = 0; memcpy( &host, in, sizeof(host) ); uint32_t dest = htob_u32( host ); QVERIFY_EQ( 0, memcmp( &dest, out, sizeof(dest) ) ); } { int32_t host = 0; memcpy( &host, in, sizeof(host) ); int32_t dest = htob_32( host ); QVERIFY_EQ( 0, memcmp( &dest, out, sizeof(dest) ) ); } } void testBig16() { uint8_t in[2] = { 0x01, 0x02 }; uint8_t out[2] = { 0x02, 0x01 }; // big to host { uint16_t source = 0; memcpy( &source, in, sizeof(source) ); uint16_t host = btoh_u16( source ); QVERIFY_EQ( 0, memcmp( &host, out, sizeof(host) ) ); } { int16_t source = 0; memcpy( &source, in, sizeof(source) ); int16_t host = btoh_16( source ); QVERIFY_EQ( 0, memcmp( &host, out, sizeof(host) ) ); } // host to big { uint16_t host = 0; memcpy( &host, in, sizeof(host) ); uint16_t dest = htob_u16( host ); QVERIFY_EQ( 0, memcmp( &dest, out, sizeof(dest) ) ); } { int16_t host = 0; memcpy( &host, in, sizeof(host) ); int16_t dest = htob_16( host ); QVERIFY_EQ( 0, memcmp( &dest, out, sizeof(dest) ) ); } } void testBigFloat() { uint8_t in[4] = { 0x01, 0x02, 0x03, 0x04 }; uint8_t out[4] = { 0x04, 0x03, 0x02, 0x01 }; // big to host { float source = 0; memcpy( &source, in, sizeof(source) ); float host = btoh_float( source ); QVERIFY_EQ( 0, memcmp( &host, out, sizeof(host) ) ); } // host to big { float host = 0; memcpy( &host, in, sizeof(host) ); float dest = htob_float( host ); QVERIFY_EQ( 0, memcmp( &dest, out, sizeof(dest) ) ); } } }; QTEST_MAIN(BigEndianTest) #include "big_endian_test.moc" mm3d-master/src/tests/libmm3d/memutil_test.cc000066400000000000000000000247731324021725400215260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests local_ptr.h, local_array.h, release_ptr.h, // and file_closer.h #include #include #include #include #include "test_common.h" #include "local_ptr.h" #include "local_array.h" #include "release_ptr.h" #include "file_closer.h" class CountObject { public: CountObject( int val = 0 ) : m_val(val) { ++s_count; } ~CountObject() { --s_count; } static int s_count; int m_val; }; /* static */ int CountObject::s_count = 0; class ReleaseObject { public: ReleaseObject( int val = 0 ) : m_val(val) { ++s_count; } void release() const { delete this; } static int s_count; int m_val; private: ~ReleaseObject() { --s_count; } }; /* static */ int ReleaseObject::s_count = 0; class MemUtilTest : public QObject { Q_OBJECT private slots: void testLocalPtr() { QVERIFY_EQ( 0, CountObject::s_count ); // Mutable { local_ptr< CountObject > ptr( new CountObject(1) ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, CountObject::s_count ); CountObject * obj = new CountObject(2); QVERIFY_EQ( 2, CountObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); CountObject * temp = ptr = obj; QVERIFY_EQ( 1, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 2, ptr->m_val ); QVERIFY_EQ( 2, temp->m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, CountObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new CountObject(3); QVERIFY_EQ( 1, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 3, ptr->m_val ); ptr->m_val = 4; QVERIFY_EQ( 4, ptr->m_val ); } QVERIFY_EQ( 0, CountObject::s_count ); // Mutable, const object { local_ptr< const CountObject > ptr = new CountObject(1); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, CountObject::s_count ); CountObject * obj = new CountObject(2); QVERIFY_EQ( 2, CountObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); const CountObject * temp = ptr = obj; QVERIFY_EQ( 1, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 2, ptr->m_val ); QVERIFY_EQ( 2, temp->m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, CountObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new CountObject(3); QVERIFY_EQ( 1, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 3, ptr->m_val ); } QVERIFY_EQ( 0, CountObject::s_count ); // Const { const local_ptr< CountObject > ptr = new CountObject(1); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, CountObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); } QVERIFY_EQ( 0, CountObject::s_count ); } void testLocalArray() { QVERIFY_EQ( 0, CountObject::s_count ); // Mutable { local_array< CountObject > ptr( new CountObject[10] ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 10, CountObject::s_count ); CountObject * obj = new CountObject[20]; obj[0].m_val = 7; QVERIFY_EQ( 30, CountObject::s_count ); QVERIFY_EQ( 0, ptr.get()[0].m_val ); CountObject * temp = ptr = obj; QVERIFY_EQ( 20, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 7, ptr.get()[0].m_val ); QVERIFY_EQ( 7, temp[0].m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, CountObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new CountObject[5]; QVERIFY_EQ( 5, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); } QVERIFY_EQ( 0, CountObject::s_count ); // Mutable, const object { local_array< CountObject > ptr( new CountObject[10] ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 10, CountObject::s_count ); CountObject * obj = new CountObject[20]; obj[0].m_val = 7; QVERIFY_EQ( 30, CountObject::s_count ); QVERIFY_EQ( 0, ptr.get()[0].m_val ); const CountObject * temp = ptr = obj; QVERIFY_EQ( 20, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 7, ptr.get()[0].m_val ); QVERIFY_EQ( 7, temp[0].m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, CountObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new CountObject[5]; QVERIFY_EQ( 5, CountObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); } QVERIFY_EQ( 0, CountObject::s_count ); // Const { const local_array< CountObject > ptr( new CountObject[10] ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 10, CountObject::s_count ); QVERIFY_EQ( 0, ptr.get()[0].m_val ); } QVERIFY_EQ( 0, CountObject::s_count ); } void testReleasePtr() { QVERIFY_EQ( 0, ReleaseObject::s_count ); // Mutable { release_ptr< ReleaseObject > ptr( new ReleaseObject(1) ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, ReleaseObject::s_count ); ReleaseObject * obj = new ReleaseObject(2); QVERIFY_EQ( 2, ReleaseObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); ReleaseObject * temp = ptr = obj; QVERIFY_EQ( 1, ReleaseObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 2, ptr->m_val ); QVERIFY_EQ( 2, temp->m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, ReleaseObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new ReleaseObject(3); QVERIFY_EQ( 1, ReleaseObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 3, ptr->m_val ); ptr->m_val = 4; QVERIFY_EQ( 4, ptr->m_val ); } QVERIFY_EQ( 0, ReleaseObject::s_count ); // Mutable, const object { release_ptr< const ReleaseObject > ptr = new ReleaseObject(1); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, ReleaseObject::s_count ); ReleaseObject * obj = new ReleaseObject(2); QVERIFY_EQ( 2, ReleaseObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); const ReleaseObject * temp = ptr = obj; QVERIFY_EQ( 1, ReleaseObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 2, ptr->m_val ); QVERIFY_EQ( 2, temp->m_val ); temp = NULL; ptr.reset( NULL ); QVERIFY_EQ( 0, ReleaseObject::s_count ); QVERIFY_TRUE( ptr.isnull() ); QVERIFY_TRUE( !ptr ); QVERIFY_TRUE( NULL == ptr.get() ); ptr = new ReleaseObject(3); QVERIFY_EQ( 1, ReleaseObject::s_count ); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 3, ptr->m_val ); } QVERIFY_EQ( 0, ReleaseObject::s_count ); // Const { const release_ptr< ReleaseObject > ptr = new ReleaseObject(1); QVERIFY_FALSE( ptr.isnull() ); QVERIFY_FALSE( !ptr ); QVERIFY_EQ( 1, ReleaseObject::s_count ); QVERIFY_EQ( 1, ptr->m_val ); QVERIFY_EQ( 1, (*ptr).m_val ); } QVERIFY_EQ( 0, ReleaseObject::s_count ); } void testFileCloser() { QVERIFY_EQ( 0, CountObject::s_count ); int fd; // Use lseek to tell if the file descriptor associated with the // stream is invalid (stream closed). { FILE * fp = fopen( "memutil_test.cc", "r" ); QVERIFY_TRUE( fp != NULL ); if ( !fp ) return; fd = fileno( fp ); file_closer fc( fp ); QVERIFY_EQ( 0, (int) lseek(fd, 0, SEEK_SET ) ); FILE * fp2 = fopen( "memutil_test.cc", "r" ); QVERIFY_TRUE( fp2 != NULL ); if ( !fp2 ) return; // This should close the original FILE* fc = fp2; QVERIFY_NE( 0, (int) lseek(fd, 0, SEEK_SET ) ); QVERIFY_EQ( EBADF, errno ); fd = fileno( fp2 ); QVERIFY_EQ( 0, (int) lseek(fd, 0, SEEK_SET ) ); // Going out of scope will close the second FILE* } QVERIFY_NE( 0, (int) lseek(fd, 0, SEEK_SET ) ); QVERIFY_EQ( EBADF, errno ); } }; QTEST_MAIN(MemUtilTest) #include "memutil_test.moc" mm3d-master/src/tests/libmm3d/misc_test.cc000066400000000000000000000423721324021725400210000ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests misc.h #include #include #include #include #include #include "misc.h" #include "log.h" #include "test_common.h" class MiscTest : public QObject { Q_OBJECT private slots: void initTestCase() { log_enable_debug( false ); } void testPathIsAbsolute() { // Win32 QVERIFY_TRUE( pathIsAbsolute( "c:\\windows\\system32" ) ); QVERIFY_TRUE( pathIsAbsolute( "c:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "a:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "z:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "A:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "C:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "Z:\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "\\" ) ); QVERIFY_TRUE( pathIsAbsolute( "\\windows\\system32" ) ); QVERIFY_FALSE( pathIsAbsolute( "windows\\system32" ) ); // Unix QVERIFY_TRUE( pathIsAbsolute( "/" ) ); QVERIFY_TRUE( pathIsAbsolute( "/etc/hosts" ) ); QVERIFY_FALSE( pathIsAbsolute( "etc/hosts" ) ); QVERIFY_FALSE( pathIsAbsolute( "" ) ); QVERIFY_FALSE( pathIsAbsolute( "." ) ); QVERIFY_FALSE( pathIsAbsolute( "./" ) ); } void testGetFilePath() { QVERIFY_EQ( std::string("/"), getFilePathFromPath( "/" ) ); QVERIFY_EQ( std::string("/"), getFilePathFromPath( "/etc" ) ); QVERIFY_EQ( std::string("/etc"), getFilePathFromPath( "/etc/hosts" ) ); QVERIFY_EQ( std::string("/home/user/.mm3d"), getFilePathFromPath( "/home/user/.mm3d/mm3drc" ) ); QVERIFY_EQ( std::string(".mm3d"), getFilePathFromPath( ".mm3d/mm3drc" ) ); QVERIFY_EQ( std::string("some/longer/dir"), getFilePathFromPath( "some/longer/dir/file" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( "./file.txt" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( "file.txt" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( "./" ) ); QVERIFY_EQ( std::string("some/dir"), getFilePathFromPath( "some/dir/" ) ); QVERIFY_EQ( std::string("\\"), getFilePathFromPath( "\\" ) ); QVERIFY_EQ( std::string("\\"), getFilePathFromPath( "\\etc" ) ); QVERIFY_EQ( std::string("\\etc"), getFilePathFromPath( "\\etc\\hosts" ) ); QVERIFY_EQ( std::string("\\home\\user\\.mm3d"), getFilePathFromPath( "\\home\\user\\.mm3d\\mm3drc" ) ); QVERIFY_EQ( std::string(".mm3d"), getFilePathFromPath( ".mm3d\\mm3drc" ) ); QVERIFY_EQ( std::string("some\\longer\\dir"), getFilePathFromPath( "some\\longer\\dir\\file" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( ".\\file.txt" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( "file.txt" ) ); QVERIFY_EQ( std::string("."), getFilePathFromPath( ".\\" ) ); QVERIFY_EQ( std::string("some\\dir"), getFilePathFromPath( "some\\dir\\" ) ); } void testGetFileName() { QVERIFY_EQ( std::string(""), getFileNameFromPath( "/" ) ); QVERIFY_EQ( std::string("etc"), getFileNameFromPath( "/etc" ) ); QVERIFY_EQ( std::string("hosts"), getFileNameFromPath( "/etc/hosts" ) ); QVERIFY_EQ( std::string("mm3drc"), getFileNameFromPath( "/home/user/.mm3d/mm3drc" ) ); QVERIFY_EQ( std::string("mm3drc"), getFileNameFromPath( ".mm3d/mm3drc" ) ); QVERIFY_EQ( std::string("file"), getFileNameFromPath( "some/longer/dir/file" ) ); QVERIFY_EQ( std::string("file.txt"), getFileNameFromPath( "./file.txt" ) ); QVERIFY_EQ( std::string("file.txt"), getFileNameFromPath( "file.txt" ) ); QVERIFY_EQ( std::string(""), getFileNameFromPath( "./" ) ); QVERIFY_EQ( std::string(""), getFileNameFromPath( "some/dir/" ) ); QVERIFY_EQ( std::string(""), getFileNameFromPath( "\\" ) ); QVERIFY_EQ( std::string("etc"), getFileNameFromPath( "\\etc" ) ); QVERIFY_EQ( std::string("hosts"), getFileNameFromPath( "\\etc\\hosts" ) ); QVERIFY_EQ( std::string("mm3drc"), getFileNameFromPath( "\\home\\user\\.mm3d\\mm3drc" ) ); QVERIFY_EQ( std::string("mm3drc"), getFileNameFromPath( ".mm3d\\mm3drc" ) ); QVERIFY_EQ( std::string("file"), getFileNameFromPath( "some\\longer\\dir\\file" ) ); QVERIFY_EQ( std::string("file.txt"), getFileNameFromPath( ".\\file.txt" ) ); QVERIFY_EQ( std::string("file.txt"), getFileNameFromPath( "file.txt" ) ); QVERIFY_EQ( std::string(""), getFileNameFromPath( ".\\" ) ); QVERIFY_EQ( std::string(""), getFileNameFromPath( "some\\dir\\" ) ); } void testRemoveExtension() { QVERIFY_EQ( std::string("file"), removeExtension("file.txt") ); QVERIFY_EQ( std::string("a"), removeExtension("a.txt") ); QVERIFY_EQ( std::string("/etc/file"), removeExtension("/etc/file.txt") ); QVERIFY_EQ( std::string("file"), removeExtension("file") ); QVERIFY_EQ( std::string("/etc/file"), removeExtension("/etc/file") ); QVERIFY_EQ( std::string("dir/file"), removeExtension("dir/file.txt") ); QVERIFY_EQ( std::string("dir/file"), removeExtension("dir/file") ); QVERIFY_EQ( std::string("dir.ext/file"), removeExtension("dir.ext/file.txt") ); QVERIFY_EQ( std::string("dir.ext/file"), removeExtension("dir.ext/file") ); QVERIFY_EQ( std::string("dir.ext/.dotfile"), removeExtension("dir.ext/.dotfile") ); QVERIFY_EQ( std::string("dir.ext/a"), removeExtension("dir.ext/a.ext") ); } void testReplaceExtension() { QVERIFY_EQ( std::string("file.new"), replaceExtension("file.txt", "new") ); QVERIFY_EQ( std::string("a.new"), replaceExtension("a.txt", "new") ); QVERIFY_EQ( std::string("/etc/file.new"), replaceExtension("/etc/file.txt", "new") ); QVERIFY_EQ( std::string("file.new"), replaceExtension("file", "new") ); QVERIFY_EQ( std::string("/etc/file.new"), replaceExtension("/etc/file", "new") ); QVERIFY_EQ( std::string("dir/file.new"), replaceExtension("dir/file.txt", "new") ); QVERIFY_EQ( std::string("dir/file.new"), replaceExtension("dir/file", "new") ); QVERIFY_EQ( std::string("dir.ext/file.new"), replaceExtension("dir.ext/file.txt", "new") ); QVERIFY_EQ( std::string("dir.ext/file.new"), replaceExtension("dir.ext/file", "new") ); QVERIFY_EQ( std::string("dir.ext/.dotfile.new"), replaceExtension("dir.ext/.dotfile", "new") ); QVERIFY_EQ( std::string("dir.ext/a.new"), replaceExtension("dir.ext/a.ext", "new") ); } void testReplaceBackslash() { std::string str; str = ""; replaceBackslash( str ); QVERIFY_EQ( std::string(""), str ); str = "some str"; replaceBackslash( str ); QVERIFY_EQ( std::string("some str"), str ); str = "\\some\\str\\"; replaceBackslash( str ); QVERIFY_EQ( std::string("/some/str/"), str ); str = "/some/str/"; replaceBackslash( str ); QVERIFY_EQ( std::string("/some/str/"), str ); char cstr[20]; strcpy( cstr, "" ); replaceBackslash( cstr ); QVERIFY_EQ( std::string(""), std::string(cstr) ); strcpy( cstr, "some cstr" ); replaceBackslash( cstr ); QVERIFY_EQ( std::string("some cstr"), std::string(cstr) ); strcpy( cstr, "\\some\\cstr\\" ); replaceBackslash( cstr ); QVERIFY_EQ( std::string("/some/cstr/"), std::string(cstr) ); strcpy( cstr, "/some/cstr/" ); replaceBackslash( cstr ); QVERIFY_EQ( std::string("/some/cstr/"), std::string(cstr) ); } void testReplaceSlash() { std::string str; str = ""; replaceSlash( str ); QVERIFY_EQ( std::string(""), str ); str = "some str"; replaceSlash( str ); QVERIFY_EQ( std::string("some str"), str ); str = "\\some\\str\\"; replaceSlash( str ); QVERIFY_EQ( std::string("\\some\\str\\"), str ); str = "/some/str/"; replaceSlash( str ); QVERIFY_EQ( std::string("\\some\\str\\"), str ); char cstr[20]; strcpy( cstr, "" ); replaceSlash( cstr ); QVERIFY_EQ( std::string(""), std::string(cstr) ); strcpy( cstr, "some cstr" ); replaceSlash( cstr ); QVERIFY_EQ( std::string("some cstr"), std::string(cstr) ); strcpy( cstr, "\\some\\cstr\\" ); replaceSlash( cstr ); QVERIFY_EQ( std::string("\\some\\cstr\\"), std::string(cstr) ); strcpy( cstr, "/some/cstr/" ); replaceSlash( cstr ); QVERIFY_EQ( std::string("\\some\\cstr\\"), std::string(cstr) ); } void testGetRelativePath() { QVERIFY_EQ( std::string("file"), getRelativePath("", "file") ); QVERIFY_EQ( std::string("file"), getRelativePath("/home/dir", "file") ); QVERIFY_EQ( std::string("subdir/file"), getRelativePath("/home/dir", "subdir/file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("/home/dir", "/home/dir/file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("/home/dir/", "/home/dir/file") ); QVERIFY_EQ( std::string("./subdir/file"), getRelativePath("/home/dir/", "/home/dir/subdir/file") ); QVERIFY_EQ( std::string("file"), getRelativePath("\\home\\dir", "file") ); QVERIFY_EQ( std::string("subdir/file"), getRelativePath("\\home\\dir", "subdir\\file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("\\home\\dir", "\\home\\dir\\file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("\\home\\dir\\", "\\home\\dir\\file") ); QVERIFY_EQ( std::string("./subdir/file"), getRelativePath("\\home\\dir\\", "\\home\\dir\\subdir\\file") ); QVERIFY_EQ( std::string("file"), getRelativePath("c:\\home\\dir", "file") ); QVERIFY_EQ( std::string("subdir/file"), getRelativePath("c:\\home\\dir", "subdir\\file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("c:\\home\\dir", "c:\\home\\dir\\file") ); QVERIFY_EQ( std::string("./file"), getRelativePath("c:\\home\\dir\\", "c:\\home\\dir\\file") ); QVERIFY_EQ( std::string("./subdir/file"), getRelativePath("c:\\home\\dir\\", "c:\\home\\dir\\subdir\\file") ); } void testGetAbsolutePath() { QVERIFY_EQ( std::string("/home/dir/file"), getAbsolutePath("/home/dir", "file") ); QVERIFY_EQ( std::string("/home/dir/file"), getAbsolutePath("/home/dir/", "file") ); QVERIFY_EQ( std::string("/home/dir/file"), getAbsolutePath("/home/dir", "./file") ); QVERIFY_EQ( std::string("/home/dir/file"), getAbsolutePath("/home/dir/", "./file") ); QVERIFY_EQ( std::string("/home/file"), getAbsolutePath("/home/dir", "../file") ); QVERIFY_EQ( std::string("/home/file"), getAbsolutePath("/home/dir/", "../file") ); QVERIFY_EQ( std::string("/file"), getAbsolutePath("/home/dir", "../../file") ); QVERIFY_EQ( std::string("/file"), getAbsolutePath("/home/dir/", "../../file") ); QVERIFY_EQ( std::string("/home/dir2/file"), getAbsolutePath("/home/dir", "../dir2/file") ); QVERIFY_EQ( std::string("/home/dir2/file"), getAbsolutePath("/home/dir/", "../dir2/file") ); QVERIFY_EQ( std::string("/file"), getAbsolutePath("/home/dir", "/file") ); QVERIFY_EQ( std::string("/file"), getAbsolutePath("/home/dir/", "/file") ); QVERIFY_EQ( std::string("c:/home/dir/file"), getAbsolutePath("c:\\home\\dir", "file") ); QVERIFY_EQ( std::string("c:/home/dir/file"), getAbsolutePath("c:\\home\\dir\\", "file") ); // FIXME these should probably be / instead /* QVERIFY_EQ( std::string("c:/home/dir/file"), getAbsolutePath("c:\\home\\dir", ".\\file") ); QVERIFY_EQ( std::string("c:/home/dir/file"), getAbsolutePath("c:\\home\\dir\\", ".\\file") ); QVERIFY_EQ( std::string("c:\\file"), getAbsolutePath("c:\\home\\dir", "c:\\file") ); QVERIFY_EQ( std::string("c:\\file"), getAbsolutePath("c:\\home\\dir\\", "c:\\file") ); */ } void testUtf8ChrTrunc() { std::string str; // each char is 3 bytes str = "ひらがな"; utf8chrtrunc( str, 13 ); QVERIFY_EQ( std::string("ひらがな"), str ); str = "ひらがな"; utf8chrtrunc( str, 12 ); QVERIFY_EQ( std::string("ひらがな"), str ); str = "ひらがな"; utf8chrtrunc( str, 11 ); QVERIFY_EQ( std::string("ひらが"), str ); str = "ひらがな"; utf8chrtrunc( str, 10 ); QVERIFY_EQ( std::string("ひらが"), str ); str = "ひらがな"; utf8chrtrunc( str, 9 ); QVERIFY_EQ( std::string("ひらが"), str ); str = "ひらがな"; utf8chrtrunc( str, 8 ); QVERIFY_EQ( std::string("ひら"), str ); char cstr[20]; strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 13 ); QVERIFY_EQ( std::string("ひらがな"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 12 ); QVERIFY_EQ( std::string("ひらがな"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 11 ); QVERIFY_EQ( std::string("ひらが"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 10 ); QVERIFY_EQ( std::string("ひらが"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 9 ); QVERIFY_EQ( std::string("ひらが"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8chrtrunc( cstr, 8 ); QVERIFY_EQ( std::string("ひら"), std::string(cstr) ); } void testUtf8StrTrunc() { std::string str; // each char is 3 bytes str = "ひらがな"; utf8strtrunc( str, 5 ); QVERIFY_EQ( std::string("ひらがな"), str ); str = "ひらがな"; utf8strtrunc( str, 4 ); QVERIFY_EQ( std::string("ひらがな"), str ); str = "ひらがな"; utf8strtrunc( str, 3 ); QVERIFY_EQ( std::string("ひらが"), str ); str = "ひらがな"; utf8strtrunc( str, 2 ); QVERIFY_EQ( std::string("ひら"), str ); str = "ひらがな"; utf8strtrunc( str, 1 ); QVERIFY_EQ( std::string("ひ"), str ); str = "ひらがな"; utf8strtrunc( str, 0 ); QVERIFY_EQ( std::string(""), str ); // mixed length str = "aひbע"; utf8strtrunc( str, 5 ); QVERIFY_EQ( std::string("aひbע"), str ); str = "aひbע"; utf8strtrunc( str, 4 ); QVERIFY_EQ( std::string("aひbע"), str ); str = "aひbע"; utf8strtrunc( str, 3 ); QVERIFY_EQ( std::string("aひb"), str ); str = "aひbע"; utf8strtrunc( str, 2 ); QVERIFY_EQ( std::string("aひ"), str ); str = "aひbע"; utf8strtrunc( str, 1 ); QVERIFY_EQ( std::string("a"), str ); str = "aひbע"; utf8strtrunc( str, 0 ); QVERIFY_EQ( std::string(""), str ); char cstr[20]; strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 5 ); QVERIFY_EQ( std::string("ひらがな"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 4 ); QVERIFY_EQ( std::string("ひらがな"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 3 ); QVERIFY_EQ( std::string("ひらが"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 2 ); QVERIFY_EQ( std::string("ひら"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 1 ); QVERIFY_EQ( std::string("ひ"), std::string(cstr) ); strcpy( cstr, "ひらがな" ); utf8strtrunc( cstr, 0 ); QVERIFY_EQ( std::string(""), std::string(cstr) ); // mixed length strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 5 ); QVERIFY_EQ( std::string("aひbע"), std::string(cstr) ); strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 4 ); QVERIFY_EQ( std::string("aひbע"), std::string(cstr) ); strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 3 ); QVERIFY_EQ( std::string("aひb"), std::string(cstr) ); strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 2 ); QVERIFY_EQ( std::string("aひ"), std::string(cstr) ); strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 1 ); QVERIFY_EQ( std::string("a"), std::string(cstr) ); strcpy( cstr, "aひbע" ); utf8strtrunc( cstr, 0 ); QVERIFY_EQ( std::string(""), std::string(cstr) ); } // FIXME add tests // normalizePath (4 args) // normalizePath (2 args) // getAbsolutePath // fixAbsolutePath // fixFileCase // getFileList // file_exists // is_directory // mkpath // utf8len // utf8strtrunc // utf8chrtrunc }; QTEST_MAIN(MiscTest) #include "misc_test.moc" mm3d-master/src/tests/libmm3d/model_add_test.cc000066400000000000000000000776641324021725400217710ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests adding and removing model components, along with undo/redo. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" class ModelAddTest : public QObject { Q_OBJECT private: void undoRedo( Model * lhs, Model * rhs1, Model * rhs2 ) { QVERIFY_TRUE( lhs->propEqual( rhs2 ) ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs1 ) ); lhs->redo(); QVERIFY_TRUE( lhs->propEqual( rhs2 ) ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs1 ) ); lhs->redo(); QVERIFY_TRUE( lhs->propEqual( rhs2 ) ); } void addTriangleVertices( Model * m ) { for ( int t = 0; t < 6; ++t ) { double c = (double) (t + 1); m->addVertex( c, c, c ); m->setVertexFree( t, true ); } m->operationComplete( "Add triangle test vertices" ); } private slots: void initTestCase() { log_enable_debug( false ); } void testVertex() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1v = newTestModel(); local_ptr rhs_2v = newTestModel(); local_ptr rhs_3v = newTestModel(); local_ptr rhs_deleted_v1 = newTestModel(); local_ptr rhs_deleted_v2 = newTestModel(); local_ptr rhs_deleted_v3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); QVERIFY_EQ( 0, (int) lhs->getVertexCount() ); lhs->addVertex( 1, 1, 1 ); rhs_1v->addVertex( 1, 1, 1 ); rhs_2v->addVertex( 1, 1, 1 ); rhs_3v->addVertex( 1, 1, 1 ); rhs_deleted_v2->addVertex( 1, 1, 1 ); rhs_deleted_v3->addVertex( 1, 1, 1 ); lhs->operationComplete( "Add Vertex 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1v.get() ) ); QVERIFY_EQ( 1, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1v.get() ); lhs->addVertex( 2, 2, 2 ); rhs_2v->addVertex( 2, 2, 2 ); rhs_3v->addVertex( 2, 2, 2 ); rhs_deleted_v1->addVertex( 2, 2, 2 ); rhs_deleted_v3->addVertex( 2, 2, 2 ); lhs->operationComplete( "Add Vertex 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2v.get() ) ); QVERIFY_EQ( 2, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_1v.get(), rhs_2v.get() ); lhs->addVertex( 3, 3, 3 ); rhs_3v->addVertex( 3, 3, 3 ); rhs_deleted_v1->addVertex( 3, 3, 3 ); rhs_deleted_v2->addVertex( 3, 3, 3 ); lhs->operationComplete( "Add Vertex 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3v.get() ) ); QVERIFY_EQ( 3, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_2v.get(), rhs_3v.get() ); lhs->deleteVertex( 0 ); lhs->operationComplete( "Delete Vertex 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_v1.get() ) ); QVERIFY_EQ( 2, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_3v.get(), rhs_deleted_v1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3v.get() ) ); QVERIFY_EQ( 3, (int) lhs->getVertexCount() ); lhs->deleteVertex( 1 ); lhs->operationComplete( "Delete Vertex 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_v2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_3v.get(), rhs_deleted_v2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3v.get() ) ); QVERIFY_EQ( 3, (int) lhs->getVertexCount() ); lhs->deleteVertex( 2 ); lhs->operationComplete( "Delete Vertex 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_v3.get() ) ); QVERIFY_EQ( 2, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_3v.get(), rhs_deleted_v3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3v.get() ) ); QVERIFY_EQ( 3, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_2v.get(), rhs_3v.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_1v.get(), rhs_2v.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getVertexCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1v.get() ); } void testTriangle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1t = newTestModel(); local_ptr rhs_2t = newTestModel(); local_ptr rhs_3t = newTestModel(); local_ptr rhs_deleted_t1 = newTestModel(); local_ptr rhs_deleted_t2 = newTestModel(); local_ptr rhs_deleted_t3 = newTestModel(); addTriangleVertices( lhs.get() ); addTriangleVertices( rhs_empty.get() ); addTriangleVertices( rhs_1t.get() ); addTriangleVertices( rhs_2t.get() ); addTriangleVertices( rhs_3t.get() ); addTriangleVertices( rhs_deleted_t1.get() ); addTriangleVertices( rhs_deleted_t2.get() ); addTriangleVertices( rhs_deleted_t3.get() ); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addTriangle( 0, 1, 2 ); rhs_1t->addTriangle( 0, 1, 2 ); rhs_2t->addTriangle( 0, 1, 2 ); rhs_3t->addTriangle( 0, 1, 2 ); rhs_deleted_t2->addTriangle( 0, 1, 2 ); rhs_deleted_t3->addTriangle( 0, 1, 2 ); lhs->operationComplete( "Add Triangle 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1t.get() ) ); QVERIFY_EQ( 1, (int) lhs->getTriangleCount() ); lhs->addTriangle( 3, 4, 5 ); rhs_2t->addTriangle( 3, 4, 5 ); rhs_3t->addTriangle( 3, 4, 5 ); rhs_deleted_t1->addTriangle( 3, 4, 5 ); rhs_deleted_t3->addTriangle( 3, 4, 5 ); lhs->operationComplete( "Add Triangle 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2t.get() ) ); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); lhs->addTriangle( 1, 3, 5 ); rhs_3t->addTriangle( 1, 3, 5 ); rhs_deleted_t1->addTriangle( 1, 3, 5 ); rhs_deleted_t2->addTriangle( 1, 3, 5 ); lhs->operationComplete( "Add Triangle 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3t.get() ) ); QVERIFY_EQ( 3, (int) lhs->getTriangleCount() ); lhs->deleteTriangle( 0 ); lhs->operationComplete( "Delete Triangle 1" ); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_t1.get() ) ); undoRedo( lhs.get(), rhs_3t.get(), rhs_deleted_t1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3t.get() ) ); lhs->deleteTriangle( 1 ); lhs->operationComplete( "Delete Triangle 2" ); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_t2.get() ) ); undoRedo( lhs.get(), rhs_3t.get(), rhs_deleted_t2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3t.get() ) ); lhs->deleteTriangle( 2 ); lhs->operationComplete( "Delete Triangle 3" ); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_t3.get() ) ); undoRedo( lhs.get(), rhs_3t.get(), rhs_deleted_t3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3t.get() ) ); QVERIFY_EQ( 3, (int) lhs->getTriangleCount() ); undoRedo( lhs.get(), rhs_2t.get(), rhs_3t.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); undoRedo( lhs.get(), rhs_1t.get(), rhs_2t.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getTriangleCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1t.get() ); } void testGroup() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); local_ptr rhs_deleted_1 = newTestModel(); local_ptr rhs_deleted_2 = newTestModel(); local_ptr rhs_deleted_3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addGroup( "Group 1" ); rhs_1->addGroup( "Group 1" ); rhs_2->addGroup( "Group 1" ); rhs_3->addGroup( "Group 1" ); rhs_deleted_2->addGroup( "Group 1" ); rhs_deleted_3->addGroup( "Group 1" ); lhs->operationComplete( "Add Group 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1.get() ) ); QVERIFY_EQ( 1, (int) lhs->getGroupCount() ); lhs->addGroup( "Group 2" ); rhs_2->addGroup( "Group 2" ); rhs_3->addGroup( "Group 2" ); rhs_deleted_1->addGroup( "Group 2" ); rhs_deleted_3->addGroup( "Group 2" ); lhs->operationComplete( "Add Group 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getGroupCount() ); lhs->addGroup( "Group 3" ); rhs_3->addGroup( "Group 3" ); rhs_deleted_1->addGroup( "Group 3" ); rhs_deleted_2->addGroup( "Group 3" ); lhs->operationComplete( "Add Group 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getGroupCount() ); lhs->deleteGroup( 0 ); lhs->operationComplete( "Delete Group 1" ); QVERIFY_EQ( 2, (int) lhs->getGroupCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_1.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteGroup( 1 ); lhs->operationComplete( "Delete Group 2" ); QVERIFY_EQ( 2, (int) lhs->getGroupCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_2.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteGroup( 2 ); lhs->operationComplete( "Delete Group 3" ); QVERIFY_EQ( 2, (int) lhs->getGroupCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_3.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getGroupCount() ); undoRedo( lhs.get(), rhs_2.get(), rhs_3.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getGroupCount() ); undoRedo( lhs.get(), rhs_1.get(), rhs_2.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getGroupCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1.get() ); } void testMaterial() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); local_ptr rhs_deleted_1 = newTestModel(); local_ptr rhs_deleted_2 = newTestModel(); local_ptr rhs_deleted_3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addColorMaterial( "Material 1" ); rhs_1->addColorMaterial( "Material 1" ); rhs_2->addColorMaterial( "Material 1" ); rhs_3->addColorMaterial( "Material 1" ); rhs_deleted_2->addColorMaterial( "Material 1" ); rhs_deleted_3->addColorMaterial( "Material 1" ); lhs->operationComplete( "Add Material 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1.get() ) ); QVERIFY_EQ( 1, (int) lhs->getTextureCount() ); lhs->addColorMaterial( "Material 2" ); rhs_2->addColorMaterial( "Material 2" ); rhs_3->addColorMaterial( "Material 2" ); rhs_deleted_1->addColorMaterial( "Material 2" ); rhs_deleted_3->addColorMaterial( "Material 2" ); lhs->operationComplete( "Add Material 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getTextureCount() ); lhs->addColorMaterial( "Material 3" ); rhs_3->addColorMaterial( "Material 3" ); rhs_deleted_1->addColorMaterial( "Material 3" ); rhs_deleted_2->addColorMaterial( "Material 3" ); lhs->operationComplete( "Add Material 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getTextureCount() ); lhs->deleteTexture( 0 ); lhs->operationComplete( "Delete Material 1" ); QVERIFY_EQ( 2, (int) lhs->getTextureCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_1.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteTexture( 1 ); lhs->operationComplete( "Delete Material 2" ); QVERIFY_EQ( 2, (int) lhs->getTextureCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_2.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteTexture( 2 ); lhs->operationComplete( "Delete Material 3" ); QVERIFY_EQ( 2, (int) lhs->getTextureCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_3.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getTextureCount() ); undoRedo( lhs.get(), rhs_2.get(), rhs_3.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getTextureCount() ); undoRedo( lhs.get(), rhs_1.get(), rhs_2.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getTextureCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1.get() ); } void testJoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); local_ptr rhs_deleted_2 = newTestModel(); local_ptr rhs_deleted_3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_1->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_3->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_deleted_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_deleted_3->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0, -1 ); lhs->operationComplete( "Add Joint 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1.get() ) ); QVERIFY_EQ( 1, (int) lhs->getBoneJointCount() ); lhs->addBoneJoint( "Joint 2", 2, 2, 2, 0, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 2", 2, 2, 2, 0, 0, 0, 0 ); rhs_3->addBoneJoint( "Joint 2", 2, 2, 2, 0, 0, 0, 0 ); rhs_deleted_3->addBoneJoint( "Joint 2", 2, 2, 2, 0, 0, 0, 0 ); lhs->operationComplete( "Add Joint 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); lhs->addBoneJoint( "Joint 3", 3, 3, 3, 0, 0, 0, 0 ); rhs_3->addBoneJoint( "Joint 3", 3, 3, 3, 0, 0, 0, 0 ); rhs_deleted_2->addBoneJoint( "Joint 3", 3, 3, 3, 0, 0, 0, 0 ); lhs->operationComplete( "Add Joint 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getBoneJointCount() ); lhs->deleteBoneJoint( 1 ); lhs->operationComplete( "Delete Joint 2" ); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_2.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteBoneJoint( 2 ); lhs->operationComplete( "Delete Joint 3" ); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_3.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getBoneJointCount() ); undoRedo( lhs.get(), rhs_2.get(), rhs_3.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); undoRedo( lhs.get(), rhs_1.get(), rhs_2.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getBoneJointCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1.get() ); } void testPoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); local_ptr rhs_deleted_1 = newTestModel(); local_ptr rhs_deleted_2 = newTestModel(); local_ptr rhs_deleted_3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_1->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_2->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_3->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_deleted_2->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); rhs_deleted_3->addPoint( "Point 1", 1, 1, 1, 0, 0, 0, -1 ); lhs->operationComplete( "Add Point 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1.get() ) ); QVERIFY_EQ( 1, (int) lhs->getPointCount() ); lhs->addPoint( "Point 2", 2, 2, 2, 0, 0, 0, -1 ); rhs_2->addPoint( "Point 2", 2, 2, 2, 0, 0, 0, -1 ); rhs_3->addPoint( "Point 2", 2, 2, 2, 0, 0, 0, -1 ); rhs_deleted_1->addPoint( "Point 2", 2, 2, 2, 0, 0, 0, -1 ); rhs_deleted_3->addPoint( "Point 2", 2, 2, 2, 0, 0, 0, -1 ); lhs->operationComplete( "Add Point 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getPointCount() ); lhs->addPoint( "Point 3", 3, 3, 3, 0, 0, 0, -1 ); rhs_3->addPoint( "Point 3", 3, 3, 3, 0, 0, 0, -1 ); rhs_deleted_1->addPoint( "Point 3", 3, 3, 3, 0, 0, 0, -1 ); rhs_deleted_2->addPoint( "Point 3", 3, 3, 3, 0, 0, 0, -1 ); lhs->operationComplete( "Add Point 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getPointCount() ); lhs->deletePoint( 0 ); lhs->operationComplete( "Delete Point 1" ); QVERIFY_EQ( 2, (int) lhs->getPointCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_1.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deletePoint( 1 ); lhs->operationComplete( "Delete Point 2" ); QVERIFY_EQ( 2, (int) lhs->getPointCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_2.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deletePoint( 2 ); lhs->operationComplete( "Delete Point 3" ); QVERIFY_EQ( 2, (int) lhs->getPointCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_3.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getPointCount() ); undoRedo( lhs.get(), rhs_2.get(), rhs_3.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getPointCount() ); undoRedo( lhs.get(), rhs_1.get(), rhs_2.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getPointCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1.get() ); } void testProjection() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); local_ptr rhs_deleted_1 = newTestModel(); local_ptr rhs_deleted_2 = newTestModel(); local_ptr rhs_deleted_3 = newTestModel(); QVERIFY_TRUE( lhs->propEqual( rhs_empty.get() ) ); lhs->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); rhs_1->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); rhs_2->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); rhs_3->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); rhs_deleted_2->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); rhs_deleted_3->addProjection( "Projection 1", Model::TPT_Cylinder, 1, 1, 1); lhs->operationComplete( "Add Projection 1" ); QVERIFY_TRUE( lhs->propEqual( rhs_1.get() ) ); QVERIFY_EQ( 1, (int) lhs->getProjectionCount() ); lhs->addProjection( "Projection 2", Model::TPT_Cylinder, 2, 2, 2); rhs_2->addProjection( "Projection 2", Model::TPT_Cylinder, 2, 2, 2); rhs_3->addProjection( "Projection 2", Model::TPT_Cylinder, 2, 2, 2); rhs_deleted_1->addProjection( "Projection 2", Model::TPT_Cylinder, 2, 2, 2); rhs_deleted_3->addProjection( "Projection 2", Model::TPT_Cylinder, 2, 2, 2); lhs->operationComplete( "Add Projection 2" ); QVERIFY_TRUE( lhs->propEqual( rhs_2.get() ) ); QVERIFY_EQ( 2, (int) lhs->getProjectionCount() ); lhs->addProjection( "Projection 3", Model::TPT_Cylinder, 3, 3, 3); rhs_3->addProjection( "Projection 3", Model::TPT_Cylinder, 3, 3, 3); rhs_deleted_1->addProjection( "Projection 3", Model::TPT_Cylinder, 3, 3, 3); rhs_deleted_2->addProjection( "Projection 3", Model::TPT_Cylinder, 3, 3, 3); lhs->operationComplete( "Add Projection 3" ); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getProjectionCount() ); lhs->deleteProjection( 0 ); lhs->operationComplete( "Delete Projection 1" ); QVERIFY_EQ( 2, (int) lhs->getProjectionCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_1.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_1.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteProjection( 1 ); lhs->operationComplete( "Delete Projection 2" ); QVERIFY_EQ( 2, (int) lhs->getProjectionCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_2.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_2.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); lhs->deleteProjection( 2 ); lhs->operationComplete( "Delete Projection 3" ); QVERIFY_EQ( 2, (int) lhs->getProjectionCount() ); QVERIFY_TRUE( lhs->propEqual( rhs_deleted_3.get() ) ); undoRedo( lhs.get(), rhs_3.get(), rhs_deleted_3.get() ); lhs->undo(); QVERIFY_TRUE( lhs->propEqual( rhs_3.get() ) ); QVERIFY_EQ( 3, (int) lhs->getProjectionCount() ); undoRedo( lhs.get(), rhs_2.get(), rhs_3.get() ); lhs->undo(); QVERIFY_EQ( 2, (int) lhs->getProjectionCount() ); undoRedo( lhs.get(), rhs_1.get(), rhs_2.get() ); lhs->undo(); QVERIFY_EQ( 1, (int) lhs->getProjectionCount() ); undoRedo( lhs.get(), rhs_empty.get(), rhs_1.get() ); } void testForceAddOrDelete() { local_ptr m = newTestModel(); m->forceAddOrDelete( false ); // Make sure we can add/delete before having frame anims. QVERIFY_EQ( 0, m->addVertex( 1, 1, 1 ) ); QVERIFY_EQ( 1, m->addVertex( 2, 2, 2 ) ); QVERIFY_EQ( 2, m->addVertex( 3, 3, 3 ) ); QVERIFY_EQ( 3, (int) m->getVertexCount() ); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_FRAME, "frame anim" ) ); // Now creates and deletes should fail QVERIFY_EQ( -1, m->addVertex( 4, 4, 4 ) ); QVERIFY_EQ( 3, (int) m->getVertexCount() ); QVERIFY_EQ( -1, m->addTriangle( 0, 1, 2 ) ); QVERIFY_EQ( 0, (int) m->getTriangleCount() ); QVERIFY_EQ( -1, m->addGroup( "failed group" ) ); QVERIFY_EQ( 0, (int) m->getGroupCount() ); QVERIFY_EQ( -1, m->addPoint( "failed point", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 0, (int) m->getPointCount() ); QVERIFY_EQ( 0, m->addColorMaterial( "first material" ) ); QVERIFY_EQ( 1, (int) m->getTextureCount() ); QVERIFY_EQ( 0, m->addBoneJoint( "first joint", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); QVERIFY_EQ( 0, m->addProjection( "first projection", Model::TPT_Cylinder, 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getProjectionCount() ); m->forceAddOrDelete( true ); QVERIFY_EQ( 3, m->addVertex( 4, 4, 4 ) ); QVERIFY_EQ( 4, (int) m->getVertexCount() ); QVERIFY_EQ( 0, m->addTriangle( 0, 1, 2 ) ); QVERIFY_EQ( 1, (int) m->getTriangleCount() ); QVERIFY_EQ( 0, m->addGroup( "success group" ) ); QVERIFY_EQ( 1, (int) m->getGroupCount() ); QVERIFY_EQ( 0, m->addPoint( "success point", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getPointCount() ); QVERIFY_EQ( 1, m->addColorMaterial( "second material" ) ); QVERIFY_EQ( 2, (int) m->getTextureCount() ); QVERIFY_EQ( 1, m->addBoneJoint( "second joint", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 2, (int) m->getBoneJointCount() ); QVERIFY_EQ( 1, m->addProjection( "second projection", Model::TPT_Cylinder, 1, 1, 1 ) ); QVERIFY_EQ( 2, (int) m->getProjectionCount() ); // FIXME test delete m->forceAddOrDelete( false ); m->deleteVertex(0); QVERIFY_EQ( 4, (int) m->getVertexCount() ); m->deleteTriangle(0); QVERIFY_EQ( 1, (int) m->getTriangleCount() ); m->deleteGroup(0); QVERIFY_EQ( 1, (int) m->getGroupCount() ); m->deletePoint(0); QVERIFY_EQ( 1, (int) m->getPointCount() ); m->deleteTexture(0); QVERIFY_EQ( 1, (int) m->getTextureCount() ); m->deleteBoneJoint(1); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); m->deleteProjection(0); QVERIFY_EQ( 1, (int) m->getProjectionCount() ); m->forceAddOrDelete( true ); m->deleteVertex(0); QVERIFY_EQ( 3, (int) m->getVertexCount() ); m->deleteTriangle(0); QVERIFY_EQ( 0, (int) m->getTriangleCount() ); m->deleteGroup(0); QVERIFY_EQ( 0, (int) m->getGroupCount() ); m->deletePoint(0); QVERIFY_EQ( 0, (int) m->getPointCount() ); m->deleteTexture(0); QVERIFY_EQ( 0, (int) m->getTextureCount() ); m->deleteBoneJoint(0); QVERIFY_EQ( 0, (int) m->getBoneJointCount() ); m->deleteProjection(0); QVERIFY_EQ( 0, (int) m->getProjectionCount() ); } void testVertexFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addVertex( 0, 0, 0 ) ); // Works QVERIFY_EQ( 1, (int) m->getVertexCount() ); // In Animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addVertex( 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getVertexCount() ); } void testTriangleFailure() { local_ptr m = newTestModel(); m->addVertex( 1, 1, 1 ); m->addVertex( 2, 2, 2 ); m->addVertex( 3, 3, 3 ); m->addVertex( 4, 4, 4 ); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); // Works QVERIFY_EQ( 0, m->addTriangle( 1, 2, 3 ) ); QVERIFY_EQ( 1, (int) m->getTriangleCount() ); // Vertex out of range QVERIFY_EQ( -1, m->addTriangle( 1, 2, 4 ) ); QVERIFY_EQ( 1, (int) m->getTriangleCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addTriangle( 1, 2, 3 ) ); QVERIFY_EQ( 1, (int) m->getTriangleCount() ); } void testGroupFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addGroup( "group name" ) ); QVERIFY_EQ( 1, (int) m->getGroupCount() ); // NULL name QVERIFY_EQ( -1, m->addGroup( NULL ) ); QVERIFY_EQ( 1, (int) m->getGroupCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addVertex( 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getGroupCount() ); } void testMaterialFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addColorMaterial( "material name" ) ); QVERIFY_EQ( 1, (int) m->getTextureCount() ); // NULL texture QVERIFY_EQ( -1, m->addTexture( NULL ) ); QVERIFY_EQ( 1, (int) m->getTextureCount() ); // NULL name QVERIFY_EQ( -1, m->addColorMaterial( NULL ) ); QVERIFY_EQ( 1, (int) m->getTextureCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addColorMaterial( "failed material" ) ); QVERIFY_EQ( 1, (int) m->getTextureCount() ); } void testJointFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addBoneJoint( "joint name", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); // Bad parent QVERIFY_EQ( -1, m->addBoneJoint( "failed joint", 1, 1, 1, 0, 0, 0, 1 ) ); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); // NULL name QVERIFY_EQ( -1, m->addBoneJoint( NULL, 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addBoneJoint( "anim joint", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getBoneJointCount() ); } void testPointFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addPoint( "point name", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getPointCount() ); // Bad parent QVERIFY_EQ( -1, m->addPoint( "failed point", 1, 1, 1, 0, 0, 0, 1 ) ); QVERIFY_EQ( 1, (int) m->getPointCount() ); // NULL name QVERIFY_EQ( -1, m->addPoint( NULL, 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getPointCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addPoint( "anim point", 1, 1, 1, 0, 0, 0, -1 ) ); QVERIFY_EQ( 1, (int) m->getPointCount() ); } void testProjectionFailure() { local_ptr m = newTestModel(); QVERIFY_EQ( 0, m->addAnimation( Model::ANIMMODE_SKELETAL, "anim name" ) ); QVERIFY_EQ( 0, m->addProjection( "point name", Model::TPT_Cylinder, 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getProjectionCount() ); // NULL name QVERIFY_EQ( -1, m->addProjection( NULL, Model::TPT_Cylinder, 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getProjectionCount() ); // In animation mode m->setCurrentAnimation( Model::ANIMMODE_SKELETAL, (unsigned int) 0 ); QVERIFY_EQ( -1, m->addProjection( "anim point", Model::TPT_Cylinder, 1, 1, 1 ) ); QVERIFY_EQ( 1, (int) m->getProjectionCount() ); } // FIXME deletion // * Delete selected // * Remove orphaned vertices // * Remove flattened triangles // * Index adjustments // FIXME test joint reparenting and vertex/point assignments // FIXME undo/redo release }; QTEST_MAIN(ModelAddTest) #include "model_add_test.moc" mm3d-master/src/tests/libmm3d/model_anim_test.cc000066400000000000000000000424561324021725400221540ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests animation methods in the Model class #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" Model * loadModelOrDie( ModelFilter & filter, const char * filename ) { Model * model = new Model; model->forceAddOrDelete( true ); Model::ModelErrorE err = filter.readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "fatal: read %s: %s\n", filename, Model::errorToString( err ) ); delete model; exit( -1 ); } model->loadTextures(); model->forceAddOrDelete( true ); return model; } Model * loadMm3dOrDie( const char * filename, FileFactory * factory = NULL ) { MisfitFilter f; if ( factory ) f.setFactory( factory ); return loadModelOrDie( f, filename ); } class ModelAnimTest : public QObject { Q_OBJECT private: Model * loadTestModel() { Model * model = loadMm3dOrDie( "data/model_equal_test.mm3d" ); model->setUndoEnabled( true ); return model; } private slots: void initTestCase() { log_enable_debug( false ); log_enable_warning( true ); } void testAnimAdd() { for ( int m = Model::ANIMMODE_SKELETAL; m <= Model::ANIMMODE_FRAME; ++m ) { const Model::AnimationModeE mode = static_cast( m ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); QVERIFY_EQ( 0, (int) lhs->getAnimCount( mode ) ); lhs->addAnimation( mode, "Animation A" ); rhs_1->addAnimation( mode, "Animation A" ); rhs_2->addAnimation( mode, "Animation A" ); rhs_3->addAnimation( mode, "Animation A" ); QVERIFY_EQ( 1, (int) lhs->getAnimCount( mode ) ); lhs->operationComplete( "Add animation A" ); lhs->addAnimation( mode, "Animation B" ); rhs_2->addAnimation( mode, "Animation B" ); rhs_3->addAnimation( mode, "Animation B" ); QVERIFY_EQ( 2, (int) lhs->getAnimCount( mode ) ); lhs->operationComplete( "Add animation B" ); lhs->addAnimation( mode, "Animation C" ); rhs_3->addAnimation( mode, "Animation C" ); QVERIFY_EQ( 3, (int) lhs->getAnimCount( mode ) ); lhs->operationComplete( "Add animation C" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } } void testAnimDelete() { for ( int m = Model::ANIMMODE_SKELETAL; m <= Model::ANIMMODE_FRAME; ++m ) { const Model::AnimationModeE mode = static_cast( m ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addAnimation( mode, "Animation A" ); rhs_1->addAnimation( mode, "Animation A" ); rhs_2->addAnimation( mode, "Animation A" ); rhs_3->addAnimation( mode, "Animation A" ); lhs->addAnimation( mode, "Animation B" ); rhs_1->addAnimation( mode, "Animation B" ); lhs->addAnimation( mode, "Animation C" ); rhs_1->addAnimation( mode, "Animation C" ); rhs_2->addAnimation( mode, "Animation C" ); QVERIFY_EQ( 3, (int) lhs->getAnimCount( mode ) ); lhs->operationComplete( "Add animations" ); lhs->deleteAnimation( mode, 1 ); lhs->operationComplete( "Delete animation B" ); QVERIFY_EQ( 2, (int) lhs->getAnimCount( mode ) ); lhs->deleteAnimation( mode, 1 ); lhs->operationComplete( "Delete animation C" ); QVERIFY_EQ( 1, (int) lhs->getAnimCount( mode ) ); lhs->deleteAnimation( mode, 0 ); lhs->operationComplete( "Delete animation A" ); QVERIFY_EQ( 0, (int) lhs->getAnimCount( mode ) ); checkUndoRedo( 4, lhs.get(), rhs_list ); } } void testAnimSetName() { for ( int m = Model::ANIMMODE_SKELETAL; m <= Model::ANIMMODE_FRAME; ++m ) { const Model::AnimationModeE mode = static_cast( m ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); lhs->addAnimation( mode, "Animation A" ); rhs_1->addAnimation( mode, "Animation A" ); rhs_2->addAnimation( mode, "Animation A" ); rhs_3->addAnimation( mode, "Rename A" ); lhs->addAnimation( mode, "Animation B" ); rhs_1->addAnimation( mode, "Animation B" ); rhs_2->addAnimation( mode, "Rename B" ); rhs_3->addAnimation( mode, "Rename B" ); lhs->operationComplete( "Add animations" ); QVERIFY_EQ( std::string("Animation A"), std::string(lhs->getAnimName(mode, 0))); QVERIFY_EQ( std::string("Animation B"), std::string(lhs->getAnimName(mode, 1))); lhs->setAnimName( mode, 1, "Rename B" ); lhs->operationComplete( "Rename animation B" ); QVERIFY_EQ( std::string("Animation A"), std::string(lhs->getAnimName(mode, 0))); QVERIFY_EQ( std::string("Rename B"), std::string(lhs->getAnimName(mode, 1))); lhs->setAnimName( mode, 0, "Rename A" ); lhs->operationComplete( "Rename animation A" ); QVERIFY_EQ( std::string("Rename A"), std::string(lhs->getAnimName(mode, 0))); QVERIFY_EQ( std::string("Rename B"), std::string(lhs->getAnimName(mode, 1))); checkUndoRedo( 3, lhs.get(), rhs_list ); } } void testAnimSetFPS() { for ( int m = Model::ANIMMODE_SKELETAL; m <= Model::ANIMMODE_FRAME; ++m ) { const Model::AnimationModeE mode = static_cast( m ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); lhs->addAnimation( mode, "Animation A" ); rhs_1->addAnimation( mode, "Animation A" ); rhs_2->addAnimation( mode, "Animation A" ); rhs_3->addAnimation( mode, "Animation A" ); lhs->addAnimation( mode, "Animation B" ); rhs_1->addAnimation( mode, "Animation B" ); rhs_2->addAnimation( mode, "Animation B" ); rhs_3->addAnimation( mode, "Animation B" ); lhs->operationComplete( "Add animations" ); double defaultFps = mode == Model::ANIMMODE_FRAME ? 10.0 : 30.0; QVERIFY_TRUE( float_equiv(defaultFps, lhs->getAnimFPS(mode, 0))); QVERIFY_TRUE( float_equiv(defaultFps, lhs->getAnimFPS(mode, 1))); lhs->setAnimFPS( mode, 0, 7.0 ); rhs_2->setAnimFPS( mode, 0, 7.0 ); rhs_3->setAnimFPS( mode, 0, 7.0 ); lhs->operationComplete( "Set FPS" ); QVERIFY_TRUE( float_equiv(7.0, lhs->getAnimFPS(mode, 0))); QVERIFY_TRUE( float_equiv(defaultFps, lhs->getAnimFPS(mode, 1))); lhs->setAnimFPS( mode, 1, 8.0 ); rhs_3->setAnimFPS( mode, 1, 8.0 ); lhs->operationComplete( "Set FPS" ); QVERIFY_TRUE( float_equiv(7.0, lhs->getAnimFPS(mode, 0))); QVERIFY_TRUE( float_equiv(8.0, lhs->getAnimFPS(mode, 1))); checkUndoRedo( 3, lhs.get(), rhs_list ); } } void testSkelAnimSetFrameCount() { local_ptr lhs = loadTestModel(); local_ptr rhs_1 = loadTestModel(); local_ptr rhs_2 = loadTestModel(); local_ptr rhs_3 = loadTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); const Model::AnimationModeE mode = Model::ANIMMODE_SKELETAL; const int animIndex = 1; QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( 8, (int) lhs->getAnimFrameCount( mode, 1 ) ); const int reduceCount = 4; lhs->setAnimFrameCount( mode, animIndex, reduceCount ); rhs_2->setAnimFrameCount( mode, animIndex, reduceCount ); rhs_3->setAnimFrameCount( mode, animIndex, reduceCount ); QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( reduceCount, (int) lhs->getAnimFrameCount( mode, 1 ) ); lhs->operationComplete( "Reduce frame count" ); const int increaseCount = 10; lhs->setAnimFrameCount( mode, animIndex, increaseCount ); rhs_3->setAnimFrameCount( mode, animIndex, increaseCount ); QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( increaseCount, (int) lhs->getAnimFrameCount( mode, 1 ) ); lhs->operationComplete( "Increase frame count" ); // Make sure increasing the frame count gave us blank frames // (instead of restoring deleted frames). const int bcount = lhs->getBoneJointCount(); for ( int f = reduceCount; f < increaseCount; f++ ) { for ( int b = 0; b < bcount; ++b ) { QVERIFY_FALSE( lhs->hasSkelAnimKeyframe( animIndex, f, b, true ) ); QVERIFY_FALSE( lhs->hasSkelAnimKeyframe( animIndex, f, b, false ) ); } } checkUndoRedo( 2, lhs.get(), rhs_list ); } void testFrameAnimSetFrameCount() { local_ptr lhs = loadTestModel(); local_ptr rhs_1 = loadTestModel(); local_ptr rhs_2 = loadTestModel(); local_ptr rhs_3 = loadTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); const Model::AnimationModeE mode = Model::ANIMMODE_FRAME; const int animIndex = 1; QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( 8, (int) lhs->getAnimFrameCount( mode, 1 ) ); const int reduceCount = 4; lhs->setAnimFrameCount( mode, animIndex, reduceCount ); rhs_2->setAnimFrameCount( mode, animIndex, reduceCount ); rhs_3->setAnimFrameCount( mode, animIndex, reduceCount ); QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( reduceCount, (int) lhs->getAnimFrameCount( mode, 1 ) ); lhs->operationComplete( "Reduce frame count" ); const int increaseCount = 10; lhs->setAnimFrameCount( mode, animIndex, increaseCount ); rhs_3->setAnimFrameCount( mode, animIndex, increaseCount ); QVERIFY_EQ( 20, (int) lhs->getAnimFrameCount( mode, 0 ) ); QVERIFY_EQ( increaseCount, (int) lhs->getAnimFrameCount( mode, 1 ) ); lhs->operationComplete( "Increase frame count" ); // Make sure increasing the frame count gave us blank frames // (instead of restoring deleted frames). double coords[3] = { 0, 0, 0 }; double acoords[3] = { 0, 0, 0 }; const int vcount = lhs->getVertexCount(); for ( int f = reduceCount; f < increaseCount; f++ ) { for ( int v = 0; v < vcount; ++v ) { lhs->getVertexCoordsUnanimated( v, coords ); lhs->getFrameAnimVertexCoords( animIndex, f, v, acoords[0], acoords[1], acoords[2] ); QVERIFY_ARRAY_EQ( coords, 3, acoords, 3 ); } } checkUndoRedo( 2, lhs.get(), rhs_list ); } void testFrameAnimSetPosition() { // Vertex { local_ptr lhs = loadTestModel(); local_ptr rhs_1 = loadTestModel(); local_ptr rhs_2 = loadTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); const int animIndex = 1; const int animFrame = 2; const int animVertex = 3; lhs->setFrameAnimVertexCoords( animIndex, animFrame, animVertex, 1.0, 2.0, 3.0 ); rhs_2->setFrameAnimVertexCoords( animIndex, animFrame, animVertex, 1.0, 2.0, 3.0 ); lhs->operationComplete( "Move vertex" ); checkUndoRedo( 1, lhs.get(), rhs_list ); } // Point Translation { local_ptr lhs = loadTestModel(); local_ptr rhs_1 = loadTestModel(); local_ptr rhs_2 = loadTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); const int animIndex = 1; const int animFrame = 2; const int animPoint = 0; lhs->setFrameAnimPointCoords( animIndex, animFrame, animPoint, 1.0, 2.0, 3.0 ); rhs_2->setFrameAnimPointCoords( animIndex, animFrame, animPoint, 1.0, 2.0, 3.0 ); lhs->operationComplete( "Move point" ); checkUndoRedo( 1, lhs.get(), rhs_list ); } // Point Rotation { local_ptr lhs = loadTestModel(); local_ptr rhs_1 = loadTestModel(); local_ptr rhs_2 = loadTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); const int animIndex = 1; const int animFrame = 2; const int animPoint = 0; lhs->setFrameAnimPointRotation( animIndex, animFrame, animPoint, 1.0, 2.0, 3.0 ); rhs_2->setFrameAnimPointRotation( animIndex, animFrame, animPoint, 1.0, 2.0, 3.0 ); lhs->operationComplete( "Rotate point" ); checkUndoRedo( 1, lhs.get(), rhs_list ); } } // FIXME add tests: // X add animation // X delete animation // x set anim name // x set anim frame count // x increase // x decrease // x get // x set anim fps // - with keyframes (check frame time adjusted) // get // ? set frame anim point count // ? set frame anim vertex count // - set frame anim point coords // x with point // ? without point // get frame anim point coords // - set frame anim point rot // x with point // ? without point // get frame anim point rot // - set frame anim vertex coords // x with vertex // ? without vertex // get // get normals // - set quick frame anim vertex coords // with vertex // - without vertex (test with undo !?) // - copy animation // - split animation // - join animations // - merge animations // - move animation // - convert anim to frame // - clear anim frame // set skel anim keyframe // add new keyframe (trans & rot) // update existing keyframe (trans & rot) // hasSkelAnimKeyframe // getSkelAnimKeyframe // interpSkelAnimKeyframe // interpSkelAnimKeyframeTime // with looping // - without looping // - delete skel anim keyframe // insert frame anim frame // - not at end of list // - set current animation by name // set current animation by index // combine name + index (is name even used?) // get // - set no animation // set current animation frame // get // set current animation time // get // - set/get looping // setup joints // x get anim count // x get anim name // undo }; QTEST_MAIN(ModelAnimTest) #include "model_anim_test.moc" mm3d-master/src/tests/libmm3d/model_equal_test.cc000066400000000000000000001647611324021725400223430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the equality functions of the model components (inner // classes), and the whole model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" class ModelEqualTest : public QObject { Q_OBJECT private: void vertexIsInitialized( Model::Vertex * v ) { QVERIFY_TRUE( v->m_visible ); QVERIFY_FALSE( v->m_selected ); QVERIFY_FALSE( v->m_free ); QVERIFY( v->m_drawSource == v->m_coord ); } void triangleIsInitialized( Model::Triangle * t ) { QVERIFY_TRUE( t->m_visible ); QVERIFY_FALSE( t->m_selected ); QVERIFY_EQ( -1, t->m_projection ); // FIXME need fuzzy EQ for floats QVERIFY( t->m_flatSource == t->m_flatNormals ); QVERIFY( t->m_normalSource[0] == t->m_finalNormals[0] ); QVERIFY( t->m_normalSource[1] == t->m_finalNormals[1] ); QVERIFY( t->m_normalSource[2] == t->m_finalNormals[2] ); } void groupIsInitialized( Model::Group * g ) { QVERIFY_EQ( std::string(""), g->m_name ); QVERIFY_EQ( -1, g->m_materialIndex ); QVERIFY_EQ( (size_t) 0, g->m_triangleIndices.size() ); QVERIFY_EQ( (uint8_t) 255, g->m_smooth ); QVERIFY_EQ( (uint8_t) 180, g->m_angle ); QVERIFY_TRUE( g->m_visible ); QVERIFY_FALSE( g->m_selected ); } void materialIsInitialized( Model::Material * m ) { QVERIFY_EQ( std::string(""), m->m_name ); QVERIFY_EQ( Model::Material::MATTYPE_TEXTURE, m->m_type ); // FIXME need fuzzy EQ for floats QVERIFY_FALSE( m->m_sClamp ); QVERIFY_FALSE( m->m_tClamp ); QVERIFY_EQ( (GLuint) 0, m->m_texture ); QVERIFY_EQ( std::string(""), m->m_filename ); QVERIFY_EQ( std::string(""), m->m_alphaFilename ); QVERIFY_TRUE( NULL == m->m_textureData ); } void initCompareInfluence( Model::InfluenceT * inf ) { inf->m_boneId = 0; inf->m_type = Model::IT_Custom; inf->m_weight = 1.0; } void initCompareVertex( Model::Vertex * v ) { v->m_visible = true; v->m_selected = false; v->m_free = true; v->m_coord[0] = 3.0; v->m_coord[1] = 4.0; v->m_coord[2] = 5.0; Model::InfluenceT inf; initCompareInfluence( &inf ); v->m_influences.clear(); v->m_influences.push_back( inf ); } void initCompareTriangle( Model::Triangle * tri ) { tri->m_visible = true; tri->m_selected = false; tri->m_projection = -1; tri->m_vertexIndices[0] = 3; tri->m_vertexIndices[1] = 4; tri->m_vertexIndices[2] = 5; tri->m_s[0] = 0.0; tri->m_s[1] = 0.5; tri->m_s[2] = 1.0; tri->m_t[0] = 1.0; tri->m_t[1] = 0.5; tri->m_t[2] = 0.0; } void initCompareGroup( Model::Group * grp ) { grp->m_name = "Group"; grp->m_visible = true; grp->m_selected = false; grp->m_angle = 90; grp->m_smooth = 127; grp->m_materialIndex = 1; grp->m_triangleIndices.clear(); grp->m_triangleIndices.insert(2); grp->m_triangleIndices.insert(4); grp->m_triangleIndices.insert(6); } void initCompareMaterial( Model::Material * mat ) { mat->m_name = "Material"; mat->m_filename = "filename.tga"; mat->m_alphaFilename = "alpha.tga"; mat->m_type = Model::Material::MATTYPE_BLANK; mat->m_ambient[0] = 0.10; mat->m_ambient[1] = 0.11; mat->m_ambient[2] = 0.12; mat->m_ambient[3] = 0.13; mat->m_diffuse[0] = 0.20; mat->m_diffuse[1] = 0.21; mat->m_diffuse[2] = 0.22; mat->m_diffuse[3] = 0.23; mat->m_specular[0] = 0.30; mat->m_specular[1] = 0.31; mat->m_specular[2] = 0.32; mat->m_specular[3] = 0.33; mat->m_emissive[0] = 0.40; mat->m_emissive[1] = 0.41; mat->m_emissive[2] = 0.42; mat->m_emissive[3] = 0.43; mat->m_shininess = 0.5; // Color is unused mat->m_sClamp = false; mat->m_tClamp = false; mat->m_texture = 0; } void initCompareMaterialAndTexture( Model::Material * mat, Texture * tex, bool alpha ) { initCompareMaterial( mat ); static uint8_t data[] = { 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xdd, 0xdd, 0xdd, 0xcc, 0xcc, 0xcc, }; static uint8_t alphaData[] = { 0xff, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x88, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x44, 0xff, 0xff, 0xff, 0xff, 0xee, 0xee, 0xee, 0xff, 0xdd, 0xdd, 0xdd, 0xff, 0xcc, 0xcc, 0xcc, 0x00, }; mat->m_type = Model::Material::MATTYPE_TEXTURE; mat->m_textureData = tex; tex->m_format = alpha ? Texture::FORMAT_RGBA : Texture::FORMAT_RGB; tex->m_data = alpha ? alphaData : data; tex->m_width = 4; tex->m_height = 4; tex->m_isBad = false; tex->m_origWidth = 16; tex->m_origHeight = 16; } uint8_t * copyTextureData( Model::Material * mat ) { Texture * tex = mat->m_textureData; size_t dataLen = ( tex->m_format == Texture::FORMAT_RGBA ) ? 4 * 4 * 4 // With alpha channel ( h * w * depth ) : 4 * 4 * 3; // Without alpha channel ( h * w * depth ) uint8_t * d = new uint8_t[ dataLen ]; memcpy( d, tex->m_data, dataLen ); tex->m_data = d; return d; } void initCompareJoint( Model::Joint * j ) { j->m_name = "Joint"; j->m_visible = true; j->m_selected = false; j->m_parent = 0; j->m_localRotation[0] = 33.3; j->m_localRotation[1] = 44.4; j->m_localRotation[2] = 55.5; j->m_localTranslation[0] = 3.0; j->m_localTranslation[1] = 4.0; j->m_localTranslation[2] = 5.0; } void initComparePoint( Model::Point * p ) { p->m_name = "Point"; p->m_type = 0; p->m_visible = true; p->m_selected = false; p->m_trans[0] = 3.0; p->m_trans[1] = 4.0; p->m_trans[2] = 5.0; p->m_rot[0] = 33.3; p->m_rot[1] = 44.4; p->m_rot[2] = 55.5; Model::InfluenceT inf; initCompareInfluence( &inf ); p->m_influences.clear(); p->m_influences.push_back( inf ); } void initCompareProjection( Model::TextureProjection * p ) { p->m_name = "Projection"; p->m_type = Model::TPT_Sphere; p->m_selected = false; p->m_pos[0] = 3.0; p->m_pos[1] = 4.0; p->m_pos[2] = 5.0; p->m_upVec[0] = 0.0; p->m_upVec[1] = 1.0; p->m_upVec[2] = 0.0; p->m_seamVec[0] = 0.0; p->m_seamVec[1] = 0.0; p->m_seamVec[2] = 1.0; // min x/y p->m_range[0][0] = 0.0; p->m_range[0][1] = 0.25; // max x/y p->m_range[1][0] = 1.0; p->m_range[1][1] = 0.75; } void initCompareBackground( Model::BackgroundImage * p ) { p->m_filename = "background.jpg"; p->m_scale = 1.0; p->m_center[0] = 3.0; p->m_center[1] = 4.0; p->m_center[2] = 5.0; } void initCompareKeyframe( Model::Keyframe * kf ) { kf->m_jointIndex = 1; kf->m_frame = 2; kf->m_time = 1.0 / 30.0; kf->m_isRotation = false; kf->m_parameter[0] = 3.0; kf->m_parameter[1] = 4.0; kf->m_parameter[2] = 5.0; } void initCompareSkelAnim( Model::SkelAnim * sa ) { sa->releaseData(); // This releases any stale keyframes sa->m_name = "Skeletal"; sa->m_fps = 30.0; sa->m_spf = 1.0 / sa->m_fps; sa->m_frameCount = 5; Model::Keyframe * kf = Model::Keyframe::get(); initCompareKeyframe( kf ); sa->m_jointKeyframes.resize( 3 ); sa->m_jointKeyframes[kf->m_jointIndex].insert_sorted( kf ); } void initCompareFrameVertex( Model::FrameAnimVertex * fav ) { fav->m_coord[0] = 3.0; fav->m_coord[1] = 4.0; fav->m_coord[2] = 5.0; } void initCompareFramePoint( Model::FrameAnimPoint * fap ) { fap->m_trans[0] = 3.0; fap->m_trans[1] = 4.0; fap->m_trans[2] = 5.0; fap->m_rot[0] = 30.0; fap->m_rot[1] = 40.0; fap->m_rot[2] = 50.0; } void initCompareFrameData( Model::FrameAnimData * fad ) { fad->releaseData(); if ( !fad->m_frameVertices ) fad->m_frameVertices = new Model::FrameAnimVertexList; if ( !fad->m_framePoints ) fad->m_framePoints = new Model::FrameAnimPointList; Model::FrameAnimVertex * fav; fav = Model::FrameAnimVertex::get(); initCompareFrameVertex(fav); fad->m_frameVertices->push_back( fav ); fav = Model::FrameAnimVertex::get(); initCompareFrameVertex(fav); fav->m_coord[0] += 10.0; fav->m_coord[1] += 10.0; fav->m_coord[2] += 10.0; fad->m_frameVertices->push_back( fav ); Model::FrameAnimPoint * fap; fap = Model::FrameAnimPoint::get(); initCompareFramePoint(fap); fad->m_framePoints->push_back( fap ); fap = Model::FrameAnimPoint::get(); initCompareFramePoint(fap); fap->m_trans[0] += 20.0; fap->m_trans[1] += 20.0; fap->m_trans[2] += 20.0; fap->m_rot[0] += 90.0; fap->m_rot[1] += 90.0; fap->m_rot[2] += 90.0; fad->m_framePoints->push_back( fap ); } void initCompareFrameAnim( Model::FrameAnim * fa ) { fa->releaseData(); fa->m_name = "Frame"; fa->m_fps = 10.0; Model::FrameAnimData * fad; fad = new Model::FrameAnimData; initCompareFrameData( fad ); fa->m_frameData.push_back( fad ); fad = new Model::FrameAnimData; initCompareFrameData( fad ); fa->m_frameData.push_back( fad ); fad = new Model::FrameAnimData; initCompareFrameData( fad ); fa->m_frameData.push_back( fad ); } private slots: void initTestCase() { log_enable_debug( false ); } // Many primitives are recycled. Test initial conditions, change conditions, // release, and re-get to make sure that the recyled primitives are properly // initialized. void testInfluenceCompare() { Model::InfluenceT lhs; Model::InfluenceT rhs; initCompareInfluence( &lhs ); initCompareInfluence( &rhs ); QVERIFY_TRUE( lhs == rhs ); rhs.m_boneId = 2; QVERIFY_FALSE( lhs == rhs ); initCompareInfluence( &rhs ); QVERIFY_TRUE( lhs == rhs ); rhs.m_type = Model::IT_Remainder; QVERIFY_FALSE( lhs == rhs ); initCompareInfluence( &rhs ); QVERIFY_TRUE( lhs == rhs ); rhs.m_weight = 0.5; QVERIFY_FALSE( lhs == rhs ); } void testVertexCompare() { Model::Vertex * lhs = Model::Vertex::get(); Model::Vertex * rhs = Model::Vertex::get(); initCompareVertex( lhs ); int bits = 0; bits = Model::PropVisibility; initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_visible = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropFree; initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_free = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropCoords; for ( int i = 0; i < 3; ++i ) { initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_coord[i] = lhs->m_coord[i] - 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } bits = Model::PropInfluences; initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_type = Model::IT_Remainder; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_weight = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.push_back( rhs->m_influences.back() ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.clear(); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); bits = Model::PropWeights; initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_type = Model::IT_Remainder; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_weight = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.push_back( rhs->m_influences.back() ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initCompareVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.clear(); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); lhs->release(); rhs->release(); } void testTriangleCompare() { Model::Triangle * lhs = Model::Triangle::get(); Model::Triangle * rhs = Model::Triangle::get(); initCompareTriangle( lhs ); int bits = 0; bits = Model::PropVisibility; initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_visible = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropProjections; initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_projection = 0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropTexCoords; for ( int i = 0; i < 3; ++i ) { initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_s[i] = rhs->m_s[i] + 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_t[i] = rhs->m_t[i] + 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } bits = Model::PropVertices; for ( int i = 0; i < 3; ++i ) { initCompareTriangle( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_vertexIndices[i] += 1; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } lhs->release(); rhs->release(); } void testGroupCompare() { Model::Group * lhs = Model::Group::get(); Model::Group * rhs = Model::Group::get(); initCompareGroup( lhs ); int bits = 0; bits = Model::PropName; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "group"; // different case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropVisibility; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_visible = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropMaterials; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_materialIndex = 2; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropNormals; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_angle = 45; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropNormals; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_smooth = 128; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropTriangles; initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 6 ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 6 ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 1 ); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 6 ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 6 ); rhs->m_triangleIndices.insert( 7 ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 6 ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 2 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 5 ); rhs->m_triangleIndices.insert( 6 ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); // Same triangles in a different order, this is legal for propEqual models initCompareGroup( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_triangleIndices.clear(); rhs->m_triangleIndices.insert( 6 ); rhs->m_triangleIndices.insert( 4 ); rhs->m_triangleIndices.insert( 2 ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); lhs->release(); rhs->release(); } void testMaterialCompare() { Model::Material * lhs = Model::Material::get(); Model::Material * rhs = Model::Material::get(); initCompareMaterial( lhs ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_texture = 2; // This only matters to OpenGL QVERIFY_TRUE( lhs->propEqual( *rhs ) ); int bits = 0; bits = Model::PropName; initCompareMaterial( lhs ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "material"; // different case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropPaths; initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_filename = "filename.jpg"; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterial( lhs ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_alphaFilename = "alpha.gif"; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropType; initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_type = Model::Material::MATTYPE_TEXTURE; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropLighting; for ( int i = 0; i < 4; i++ ) { initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_ambient[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_diffuse[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_specular[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_emissive[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_shininess = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropClamp; initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_sClamp = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterial( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_tClamp = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); // FIXME these checks really belong in the texture testing code. I do want to keep // at least one check below to make sure that the propEquality test fails if the // texture compare fails. local_ptr tex_lhs = new Texture(); local_ptr tex_rhs = new Texture(); bits = Model::PropPixels; initCompareMaterialAndTexture( lhs, tex_lhs.get(), false ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), false ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_format = Texture::FORMAT_RGBA; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( lhs, tex_lhs.get(), true ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_format = Texture::FORMAT_RGB; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_width = 2; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_height = 2; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_origWidth = 2; // Compare doesn't care rhs->m_textureData->m_origHeight = 2; QVERIFY_TRUE( lhs->propEqual( *rhs ) ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_isBad = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); lhs->m_textureData->m_isBad = true; // Even if both are bad, it's not a match rhs->m_textureData->m_isBad = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareMaterialAndTexture( lhs, tex_lhs.get(), true ); for ( int i = 0; i < 4; ++i ) { initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); local_array buf = copyTextureData( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_data[i] = 0x48; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); tex_rhs->m_data = NULL; } // The last element has an alpha value of 0, so changes to the color channels // should not result in a texture mismatch. for ( int i = 0; i < 3; ++i ) { initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); local_array buf = copyTextureData( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_data[15 * 4 + i] = 0x48; QVERIFY_TRUE( lhs->propEqual( *rhs ) ); // Clear, don't care tex_rhs->m_data = NULL; } // Same as above, except the alpha channel is no longer clear. for ( int i = 0; i < 3; ++i ) { initCompareMaterialAndTexture( lhs, tex_lhs.get(), true ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), true ); local_array buf = copyTextureData( rhs ); local_array buf2 = copyTextureData( lhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_data[15 * 4 + i] = 0x48; rhs->m_textureData->m_data[15 * 4 + 3] = 0x01; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); tex_rhs->m_data = NULL; tex_lhs->m_data = NULL; } initCompareMaterialAndTexture( lhs, tex_lhs.get(), false ); for ( int i = 0; i < 3; ++i ) { initCompareMaterialAndTexture( rhs, tex_rhs.get(), false ); local_array buf = copyTextureData( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_data[i] = 0x48; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); tex_rhs->m_data = NULL; } for ( int i = 0; i < 3; ++i ) { initCompareMaterialAndTexture( lhs, tex_lhs.get(), false ); initCompareMaterialAndTexture( rhs, tex_rhs.get(), false ); local_array buf = copyTextureData( rhs ); local_array buf2 = copyTextureData( lhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_textureData->m_data[i] = 0x48; rhs->m_textureData->m_data[3] = 0x00; // Not alpha, change above matters lhs->m_textureData->m_data[3] = 0x00; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); tex_rhs->m_data = NULL; tex_lhs->m_data = NULL; } // Test image data is statically allocated, don't free it tex_lhs->m_data = NULL; tex_rhs->m_data = NULL; lhs->release(); rhs->release(); } void testJointCompare() { Model::Joint * lhs = Model::Joint::get(); Model::Joint * rhs = Model::Joint::get(); initCompareJoint( lhs ); int bits = 0; bits = Model::PropName; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "joint"; // case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropVisibility; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_visible = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = 0; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_parent = 1; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, ~bits ) ); for ( int i = 0; i < 3; ++i ) { bits = Model::PropRotation; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_localRotation[i] = 11.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropCoords; initCompareJoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_localTranslation[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } lhs->release(); rhs->release(); } void testPointCompare() { Model::Point * lhs = Model::Point::get(); Model::Point * rhs = Model::Point::get(); initComparePoint( lhs ); int bits = 0; bits = Model::PropName; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "point"; // case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropType; // Point m_type doesn't actually do anything, but check it anyway. initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_type = 2; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropVisibility; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_visible = false; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); for ( int i = 0; i < 3; ++i ) { bits = Model::PropRotation; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_rot[i] = 11.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropCoords; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_trans[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } bits = Model::PropInfluences; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_type = Model::IT_Remainder; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_weight = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.push_back( rhs->m_influences.back() ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.clear(); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); bits = Model::PropWeights; initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_type = Model::IT_Remainder; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.front().m_weight = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.push_back( rhs->m_influences.back() ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); initComparePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_influences.clear(); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~(Model::PropWeights | Model::PropInfluences) ) ); lhs->release(); rhs->release(); } void testKeyframeCompare() { Model::Keyframe * lhs = Model::Keyframe::get(); Model::Keyframe * rhs = Model::Keyframe::get(); initCompareKeyframe( lhs ); int bits = 0; bits = 0; initCompareKeyframe( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_jointIndex = 2; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropTime; initCompareKeyframe( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_frame = 3; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareKeyframe( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_time = 2.0 / 30.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); for ( int i = 0; i < 3; i++ ) { bits = Model::PropRotation; initCompareKeyframe( rhs ); lhs->m_isRotation = true; rhs->m_isRotation = true; QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_parameter[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropCoords; initCompareKeyframe( rhs ); lhs->m_isRotation = false; rhs->m_isRotation = false; QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_parameter[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } // Restore m_isRotation to proper state initCompareKeyframe( lhs ); lhs->release(); rhs->release(); } void testSkelAnimCompare() { Model::SkelAnim * lhs = Model::SkelAnim::get(); Model::SkelAnim * rhs = Model::SkelAnim::get(); initCompareSkelAnim( lhs ); int bits = 0; bits = Model::PropName; initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "skeletal"; // case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropTime; initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_fps = 24.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropDimensions; initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_frameCount = 4; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropType; // Change keyframe initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_jointKeyframes[1][0]->m_isRotation = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); Model::Keyframe * kf; bits = Model::PropCoords | Model::PropRotation | Model::PropType; // Add same keyframe for a different joint initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); kf = Model::Keyframe::get(); initCompareKeyframe( kf ); kf->m_jointIndex = 0; rhs->m_jointKeyframes[kf->m_jointIndex].insert_sorted( kf ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); // Add identical keyframe as rotation for the same joint initCompareSkelAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); kf = Model::Keyframe::get(); initCompareKeyframe( kf ); kf->m_isRotation = true; rhs->m_jointKeyframes[kf->m_jointIndex].insert_sorted( kf ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); lhs->release(); rhs->release(); } void testFrameVertexCompare() { Model::FrameAnimVertex * lhs = Model::FrameAnimVertex::get(); Model::FrameAnimVertex * rhs = Model::FrameAnimVertex::get(); initCompareFrameVertex( lhs ); int bits = 0; bits = Model::PropCoords; for ( int i = 0; i < 3; i++ ) { initCompareFrameVertex( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_coord[i] = 0.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } lhs->release(); rhs->release(); } void testFramePointCompare() { Model::FrameAnimPoint * lhs = Model::FrameAnimPoint::get(); Model::FrameAnimPoint * rhs = Model::FrameAnimPoint::get(); initCompareFramePoint( lhs ); int bits = 0; for ( int i = 0; i < 3; i++ ) { bits = Model::PropCoords; initCompareFramePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_trans[i] = 0.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropRotation; initCompareFramePoint( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_rot[i] = 0.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } lhs->release(); rhs->release(); } void testFrameDataCompare() { Model::FrameAnimData lhs; Model::FrameAnimData rhs; initCompareFrameData( &lhs ); int bits = 0; bits = Model::PropCoords; initCompareFrameData( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); (*rhs.m_frameVertices)[0]->m_coord[0] = 0.0; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); initCompareFrameData( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); (*rhs.m_framePoints)[0]->m_trans[0] = 0.0; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); bits = Model::PropRotation; initCompareFrameData( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); (*rhs.m_framePoints)[0]->m_rot[0] = 0.0; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); bits = Model::PropCoords | Model::PropRotation; initCompareFrameData( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); Model::FrameAnimVertex * fav = Model::FrameAnimVertex::get(); initCompareFrameVertex( fav ); rhs.m_frameVertices->push_back(fav); QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); initCompareFrameData( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); Model::FrameAnimPoint * fap = Model::FrameAnimPoint::get(); initCompareFramePoint( fap ); rhs.m_framePoints->push_back(fap); QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); } void testFrameAnimCompare() { Model::FrameAnim * lhs = Model::FrameAnim::get(); Model::FrameAnim * rhs = Model::FrameAnim::get(); initCompareFrameAnim( lhs ); int bits = 0; bits = Model::PropName; initCompareFrameAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "frame"; // case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropTime; initCompareFrameAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_fps = 24.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropCoords | Model::PropRotation; initCompareFrameAnim( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); Model::FrameAnimData * fad = new Model::FrameAnimData; initCompareFrameData( fad ); rhs->m_frameData.push_back( fad ); QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); lhs->release(); rhs->release(); } void testProjectionCompare() { Model::TextureProjection * lhs = Model::TextureProjection::get(); Model::TextureProjection * rhs = Model::TextureProjection::get(); initCompareProjection( lhs ); int bits = 0; bits = Model::PropName; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_name = "projection"; // case QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropSelection; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_selected = true; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropType; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_type = Model::TPT_Cylinder; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); for ( int i = 0; i < 3; i++ ) { bits = Model::PropCoords; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_pos[i] = 1.0; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); bits = Model::PropRotation; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_upVec[i] = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_seamVec[i] = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } for ( int i = 0; i < 2; i++ ) { bits = Model::PropDimensions; initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_range[0][i] = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); initCompareProjection( rhs ); QVERIFY_TRUE( lhs->propEqual( *rhs ) ); rhs->m_range[1][i] = 0.5; QVERIFY_FALSE( lhs->propEqual( *rhs ) ); QVERIFY_FALSE( lhs->propEqual( *rhs, bits ) ); QVERIFY_TRUE( lhs->propEqual( *rhs, ~bits ) ); } lhs->release(); rhs->release(); } void testBackgroundCompare() { Model::BackgroundImage lhs; Model::BackgroundImage rhs; initCompareBackground( &lhs ); int bits = 0; bits = Model::PropPaths; initCompareBackground( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); rhs.m_filename = "background.png"; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); bits = Model::PropScale; initCompareBackground( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); rhs.m_scale = 0.5; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); bits = Model::PropCoords; for ( int i = 0; i < 3; i++ ) { initCompareBackground( &rhs ); QVERIFY_TRUE( lhs.propEqual( rhs ) ); rhs.m_center[i] = 1.0; QVERIFY_FALSE( lhs.propEqual( rhs ) ); QVERIFY_FALSE( lhs.propEqual( rhs, bits ) ); QVERIFY_TRUE( lhs.propEqual( rhs, ~bits ) ); } } void testModelCompare() { // FIXME test for specific CompareBits matches const char model_file[] = "data/model_equal_test.mm3d"; local_ptr lhs = loadModelOrDie( model_file ); local_ptr rhs; int parts = Model::PartAll; int props = Model::PropAll; // Vertices { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->moveVertex( 1, 3, 4, 5 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setVertexFree( 3, true ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addVertex( 3, 4, 5 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Triangles { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setTriangleVertices( 0, 2, 4, 6 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->selectTriangle( 3 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addTriangle( 3, 4, 5 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Groups { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setGroupSmooth( 1, 160 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addGroup("new group"); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Materials { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setTextureShininess( 1, 55.0f ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addColorMaterial("new material"); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Skeleton { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setBoneJointName( 1, "renamed joint" ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addBoneJoint("new joint", 0, 0, 0, // position 0, 0, 0, // rotation 0 ); // parent joint QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Meta data { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->updateMetaData( "key_1", "new value" ); QVERIFY_EQ( lhs->getMetaDataCount(), rhs->getMetaDataCount() ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addMetaData( "key_3", "new value" ); QVERIFY_EQ( lhs->getMetaDataCount() + 1, rhs->getMetaDataCount() ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Texture projections { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); double seam[3] = { 0, 1, 0 }; rhs->setProjectionSeam( 0, seam ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addProjection( "New Projection", Model::TPT_Cylinder, 0.0, 0.0, 0.0 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Background images { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setBackgroundScale( 0, 0.25f ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setBackgroundImage( 1, "data/test_rgba_comp.tga" ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } // Skeletal animation { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setSkelAnimKeyframe( 0, 0, 0, false, 1.0, 1.0, 1.0 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->deleteSkelAnimKeyframe( 0, 0, 0, false ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addAnimation( Model::ANIMMODE_SKELETAL, "new anin" ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } { rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setFrameAnimVertexCoords( 0, 0, 0, 1.0, 1.0, 1.0 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->setAnimFrameCount( Model::ANIMMODE_FRAME, 0, 25 ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); rhs = loadModelOrDie( model_file ); QVERIFY_TRUE( lhs->propEqual( rhs.get(), parts, props ) ); rhs->addAnimation( Model::ANIMMODE_FRAME, "new anin" ); QVERIFY_FALSE( lhs->propEqual( rhs.get(), parts, props ) ); } } }; QTEST_MAIN(ModelEqualTest) #include "model_equal_test.moc" mm3d-master/src/tests/libmm3d/model_equiv_test.cc000066400000000000000000002245361324021725400223620ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the equality functions of the model components (inner // classes), and the whole model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "tgatex.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" Texture * loadTextureOrDie( TextureFilter * f, const char * filename ) { Texture * tex = new Texture; Texture::ErrorE err = f->readFile( tex, filename ); if ( err != Texture::ERROR_NONE ) { fprintf( stderr, "fatal: %s: %s\n", filename, Texture::errorToString( err ) ); delete tex; exit( -1 ); } return tex; } Texture * loadTgaOrDie( const char * filename ) { TgaTextureFilter f; return loadTextureOrDie( &f, filename ); } class ModelEquivTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); log_enable_warning( true ); log_enable_error( false ); } // Many primitives are recycled. Test initial conditions, change conditions, // release, and re-get to make sure that the recyled primitives are properly // initialized. void testEmpty() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testExactCompare() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Invert triangles 0 and 1 in rhs { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 2, 1, 0 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } // Checks that one triangle doesn't match two triangles in the other model. void testNoDouble() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testDoulbedTriangle() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testOffset() { // Rotate the triangle's vertex indices and see if they still match { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 2, 0, 1 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 1, 2, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testVertexIndex() { // Re-order the vertex indices and see if they still match { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 2, 2, 2 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addTriangle( 2, 1, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 2, 2, 2 ); rhs->addVertex( 1, 1, 1 ); rhs->addTriangle( 0, 2, 1 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testInvertedNormal() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 2, 1, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 1, 0, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 2, 1 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testUnusedGroup() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Unused 1" ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Unused 2" ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testBothGrouped() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Group A" ); lhs->addTriangleToGroup( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Group B" ); rhs->addTriangleToGroup( 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Group A" ); lhs->addGroup( "Group B" ); lhs->addTriangleToGroup( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Group A" ); rhs->addGroup( "Group B" ); rhs->addTriangleToGroup( 1, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Group A" ); lhs->addGroup( "Group B" ); lhs->addTriangleToGroup( 1, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Group A" ); rhs->addGroup( "Group B" ); rhs->addTriangleToGroup( 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testOneGrouped() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Unused 1" ); lhs->addTriangleToGroup( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Unused 2" ); rhs->addTriangleToGroup( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testGroupMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Group A" ); lhs->setGroupSmooth( 0, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Group A" ); rhs->setGroupSmooth( 0, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); lhs->addTriangleToGroup( 0, 0 ); rhs->addTriangleToGroup( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Group A" ); lhs->setGroupAngle( 0, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Group A" ); rhs->setGroupAngle( 0, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); lhs->addTriangleToGroup( 0, 0 ); rhs->addTriangleToGroup( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testGroupSplit() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); lhs->addGroup( "Single" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTriangleToGroup( 0, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); rhs->addGroup( "Group A" ); rhs->addGroup( "Group B" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTriangleToGroup( 1, 1 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); lhs->addGroup( "Single" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTriangleToGroup( 0, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); rhs->addGroup( "Group A" ); rhs->addGroup( "Group B" ); rhs->addTriangleToGroup( 0, 1 ); rhs->addTriangleToGroup( 1, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); lhs->addGroup( "Group A" ); lhs->addGroup( "Group B" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTriangleToGroup( 1, 1 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); rhs->addGroup( "Single" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTriangleToGroup( 0, 1 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); lhs->addGroup( "Group A" ); lhs->addGroup( "Group B" ); lhs->addTriangleToGroup( 0, 1 ); lhs->addTriangleToGroup( 1, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addTriangle( 2, 1, 0 ); rhs->addGroup( "Single" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTriangleToGroup( 0, 1 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testCoordMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 1 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 0 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 0 ); rhs->addTriangle( 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testMaterialMatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Left Mat" ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Right Mat" ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Texture file contents differ, but pixel data matches { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr tex2 = loadTgaOrDie( "data/test_rgb_uncomp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex2.get() ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testMaterialUnmatched() { // Material property mismatch { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Left Mat" ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureShininess( 0, 0.5f ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Right Mat" ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureShininess( 0, 0.6f ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Right Material unassigned { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Left Mat" ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Right Mat" ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Left material unassigned { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Left Mat" ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Right Mat" ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Right group unassigned { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Left Mat" ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addColorMaterial( "Right Mat" ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Left group unassigned { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addColorMaterial( "Left Mat" ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Right Mat" ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Texture data mismatch { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr tex2 = loadTgaOrDie( "data/test_rgba_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex2.get() ); rhs->setGroupTextureId( 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testTexCoordMatch() { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.1, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.8 ); rhs->setTextureCoords( 0, 2, 0.3, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testTexCoordMismatch() { { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.2, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.8 ); rhs->setTextureCoords( 0, 2, 0.3, 0.7 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.1, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.9 ); rhs->setTextureCoords( 0, 2, 0.3, 0.7 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.1, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.8 ); rhs->setTextureCoords( 0, 2, 0.1, 0.7 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testTexCoordMismatchIgnored() { // No group material { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setTextureCoords( 0, 0, 0.2, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.8 ); rhs->setTextureCoords( 0, 2, 0.3, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Triangle not grouped { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.1, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.9 ); rhs->setTextureCoords( 0, 2, 0.3, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Material is not texture map { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addColorMaterial( "Mat Left" ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addColorMaterial( "Mat Right" ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.1, 0.9 ); rhs->setTextureCoords( 0, 1, 0.2, 0.8 ); rhs->setTextureCoords( 0, 2, 0.1, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testTexCoordOffset() { // Vert and tex coords rotated, match { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 2, 0, 1 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 0, 0.3, 0.7 ); rhs->setTextureCoords( 0, 1, 0.1, 0.9 ); rhs->setTextureCoords( 0, 2, 0.2, 0.8 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Only tex coords rotated, no match { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addGroup( "Left Group" ); lhs->addTriangleToGroup( 0, 0 ); lhs->addTexture( tex1.get() ); lhs->setGroupTextureId( 0, 0 ); lhs->setTextureCoords( 0, 0, 0.1, 0.9 ); lhs->setTextureCoords( 0, 1, 0.2, 0.8 ); lhs->setTextureCoords( 0, 2, 0.3, 0.7 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addGroup( "Right Group" ); rhs->addTriangleToGroup( 0, 0 ); rhs->addTexture( tex1.get() ); rhs->setGroupTextureId( 0, 0 ); rhs->setTextureCoords( 0, 2, 0.1, 0.9 ); rhs->setTextureCoords( 0, 0, 0.2, 0.8 ); rhs->setTextureCoords( 0, 1, 0.3, 0.7 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } // FIXME test influences void testPointExact() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testOnePointDoubled() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addPoint( "Left2", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right2", 5, 6, 7, 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testBothPointsDoubled() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addPoint( "Left2", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right2", 5, 6, 7, 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addPoint( "Left2", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right2", 5, 6, 7, 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testPointsInverted() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addPoint( "Left2", 4, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 4, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right2", 5, 6, 7, 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addPoint( "Left2", 5, 6, 7, 0, 3, 2 ); rhs->addPoint( "Right2", 5, 6, 7, 0, 3, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 2 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testPointCoordMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 6, 6, 7, 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 5, 7, 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 5, 0, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testPointRotMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 1, 1, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, 2 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addPoint( "Right", 5, 6, 7, 0, 1, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } // Test points where rotations angles are not equal, but describe // the same orientation. void testPointRotEquiv() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 0, 0 ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, PI, 0, 0 ); rhs->addPoint( "Right", 5, 6, 7, -PI, 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, PI, 0 ); rhs->addPoint( "Right", 5, 6, 7, 0, -PI, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 0, PI ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, -PI ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 2*PI, 0, 0 ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 2*PI, 0 ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Left", 5, 6, 7, 0, 0, 2*PI ); rhs->addPoint( "Right", 5, 6, 7, 0, 0, 0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testJointExact() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testOneJointDoubled() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testBothJointsDoubled() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); lhs->addBoneJoint( "Left B", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right B", 2, 3, 4, 1, 1, 1, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testJointsInverted() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); lhs->addBoneJoint( "Left B", 3, 4, 5, 2, 2, 2, 0); lhs->addBoneJoint( "Left A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right A", 2, 3, 4, 1, 1, 1, 0); rhs->addBoneJoint( "Right B", 3, 4, 5, 2, 2, 2, 0); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testJointCoordMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 6, 6, 7, 0, 1, 2 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 5, 5, 7, 0, 1, 2 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 5, 6, 5, 0, 1, 2 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testJointRotMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 5, 6, 7, 1, 1, 2 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 0, 2 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 1, 2 ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 1, 1 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } // Test joints where rotations angles are not equal, but describe // the same orientation. void testJointRotEquiv() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, PI, 0, 0 ); rhs->addBoneJoint( "Right", 5, 6, 7, -PI, 0, 0 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, PI, 0 ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, -PI, 0 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 0, PI ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 0, -PI ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 2*PI, 0, 0 ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 0, 0 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 2*PI, 0 ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 0, 0 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 5, 6, 7, 0, 0, 2*PI ); rhs->addBoneJoint( "Right", 5, 6, 7, 0, 0, 0 ); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } void testParentDoubled() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); lhs->addBoneJoint( "Left B", 2, 2, 2, 0, 0, 0, 0); lhs->addBoneJoint( "Left AA", 3, 3, 3, 0, 0, 0, 1); rhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); rhs->addBoneJoint( "Left B", 2, 2, 2, 0, 0, 0, 0); rhs->addBoneJoint( "Left BB", 3, 3, 3, 0, 0, 0, 2); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testParentMismatch() { // Absolute position is the same, different parent { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0); lhs->addBoneJoint( "Left C", 4, 4, 4, 0, 0, 0, 1); rhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); rhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0); rhs->addBoneJoint( "Left C", 4, 4, 4, 0, 0, 0, 2); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Relative position is the same, different parent { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0); lhs->addBoneJoint( "Left C", 4, 4, 4, 0, 0, 0, 1); rhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0); rhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0); rhs->addBoneJoint( "Left C", 5, 5, 5, 0, 0, 0, 2); lhs->setupJoints(); rhs->setupJoints(); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testVertexInfluence() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testVertexInfluenceMissing() { // Missing Right { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Missing Left { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testVertexInfluenceMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 1, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 1.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testVertexInfluenceOffset() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 2, 0, 1 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.5 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testVertexInfluenceMultiple() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); rhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.3 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testVertexInfluenceWeighted() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.50 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.25 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.20 ); rhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.10 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testVertexInfluenceInverted() { // Invert bone joint order for 1 and 2 { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); rhs->addVertexInfluence( 1, 2, Model::IT_Custom, 0.3 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Invert influence order. { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } // Test that a weight of zero counts as no influence void testVertexInfluenceZero() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 2, 2, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.50 ); lhs->addVertexInfluence( 1, 1, Model::IT_Custom, 0.0 ); rhs->addVertex( 0, 0, 0 ); rhs->addVertex( 1, 1, 1 ); rhs->addVertex( 2, 2, 2 ); rhs->addTriangle( 0, 1, 2 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addVertexInfluence( 1, 0, Model::IT_Custom, 0.20 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testPointInfluence() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testPointInfluenceMissing() { // Missing Right { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } // Missing Left { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testPointInfluenceMismatch() { { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 1, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 1.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); QVERIFY_FALSE( lhs->equivalent( rhs.get() ) ); } } void testPointInfluenceOffset() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 1.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.5 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testPointInfluenceMultiple() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); rhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.3 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testPointInfluenceWeighted() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.50 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.25 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.20 ); rhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.10 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } void testPointInfluenceInverted() { // Invert bone joint order for 1 and 2 { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); rhs->addPointInfluence( 1, 2, Model::IT_Custom, 0.3 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // Invert influence order. { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.3 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.7 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } } // Test that a weight of zero counts as no influence void testPointInfluenceZero() { local_ptr lhs = newTestModel(); local_ptr rhs = newTestModel(); lhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); lhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); lhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); lhs->addBoneJoint( "Left", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Left A", 2, 2, 2, 0, 0, 0, 0 ); lhs->addBoneJoint( "Left B", 3, 3, 3, 0, 0, 0, 0 ); lhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.50 ); lhs->addPointInfluence( 1, 1, Model::IT_Custom, 0.0 ); rhs->addPoint( "Point", 0, 0, 0, 0, 0, 0 ); rhs->addPoint( "Point", 1, 1, 1, 0, 0, 0 ); rhs->addPoint( "Point", 2, 2, 2, 0, 0, 0 ); rhs->addBoneJoint( "Right", 1, 1, 1, 0, 0, 0 ); rhs->addBoneJoint( "Right A", 2, 2, 2, 0, 0, 0, 0 ); rhs->addBoneJoint( "Right B", 3, 3, 3, 0, 0, 0, 0 ); rhs->addPointInfluence( 1, 0, Model::IT_Custom, 0.20 ); QVERIFY_TRUE( lhs->equivalent( rhs.get() ) ); } // FIXME // * Test influence weight mismatch // * Test animations }; // FIXME remove tolerance QTEST_MAIN(ModelEquivTest) #include "model_equiv_test.moc" mm3d-master/src/tests/libmm3d/model_group_test.cc000066400000000000000000000304761324021725400223630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests group methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" class ModelGroupTest : public QObject { Q_OBJECT private: void checkGroupContents( std::list & lhs, Model * m, int grp ) { std::list rhs; if ( grp >= 0 ) rhs = m->getGroupTriangles( grp ); else rhs = m->getUngroupedTriangles(); lhs.sort(); rhs.sort(); QVERIFY_TRUE( lhs == rhs ); std::list::const_iterator it = lhs.begin(); int tcount = m->getTriangleCount(); for ( int t = 0; t < tcount; ++t ) { if ( it != lhs.end() && *it == t ) { QVERIFY_EQ( grp, m->getTriangleGroup( *it ) ); ++it; } else { QVERIFY_NE( grp, m->getTriangleGroup( t ) ); } } } void addTriangleTest( std::list & lhs, Model * m, int grp, int tri ) { m->addTriangleToGroup( grp, tri ); lhs.push_back( tri ); checkGroupContents( lhs, m, grp ); } void removeTriangleTest( std::list & lhs, Model * m, int grp, int tri ) { m->removeTriangleFromGroup( grp, tri ); lhs.remove( tri ); checkGroupContents( lhs, m, grp ); QVERIFY_NE( grp, m->getTriangleGroup( tri ) ); } void removeAll( Model * m, int grp ) { list tris = m->getGroupTriangles( grp ); while ( !tris.empty() ) { m->removeTriangleFromGroup( grp, tris.front() ); tris.pop_front(); } } private slots: void initTestCase() { log_enable_debug( false ); } // FIXME add more tests void testGroupName() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_firstname = newTestModel(); local_ptr rhs_secondname = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_firstname.get() ); rhs_list.push_back( rhs_secondname.get() ); lhs->addGroup( "Group A" ); lhs->addGroup( "First Name" ); lhs->addGroup( "Group B" ); rhs_firstname->addGroup( "Group A" ); rhs_firstname->addGroup( "First Name" ); rhs_firstname->addGroup( "Group B" ); rhs_secondname->addGroup( "Group A" ); rhs_secondname->addGroup( "Second Name" ); rhs_secondname->addGroup( "Group B" ); QVERIFY_EQ( std::string("Group A"), std::string(lhs->getGroupName(0))); QVERIFY_EQ( std::string("First Name"), std::string(lhs->getGroupName(1))); QVERIFY_EQ( std::string("Group B"), std::string(lhs->getGroupName(2))); QVERIFY_EQ( 0, lhs->getGroupByName("Group A")); QVERIFY_EQ( 1, lhs->getGroupByName("First Name")); QVERIFY_EQ( 2, lhs->getGroupByName("Group B")); QVERIFY_EQ( -1, lhs->getGroupByName("Second Name")); lhs->operationComplete( "Add groups" ); lhs->setGroupName(1, "Second Name" ); QVERIFY_EQ( std::string("Group A"), std::string(lhs->getGroupName(0))); QVERIFY_EQ( std::string("Second Name"), std::string(lhs->getGroupName(1))); QVERIFY_EQ( std::string("Group B"), std::string(lhs->getGroupName(2))); QVERIFY_EQ( 0, lhs->getGroupByName("Group A")); QVERIFY_EQ( 1, lhs->getGroupByName("Second Name")); QVERIFY_EQ( 2, lhs->getGroupByName("Group B")); QVERIFY_EQ( -1, lhs->getGroupByName("First Name")); lhs->operationComplete( "Set group name" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testGroupAngle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_first = newTestModel(); local_ptr rhs_second = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_first.get() ); rhs_list.push_back( rhs_second.get() ); lhs->addGroup( "Group A" ); lhs->addGroup( "Group B" ); lhs->addGroup( "Group C" ); rhs_first->addGroup( "Group A" ); rhs_first->addGroup( "Group B" ); rhs_first->addGroup( "Group C" ); rhs_second->addGroup( "Group A" ); rhs_second->addGroup( "Group B" ); rhs_second->addGroup( "Group C" ); lhs->setGroupSmooth( 0, 10 ); lhs->setGroupSmooth( 1, 20 ); lhs->setGroupSmooth( 2, 30 ); rhs_first->setGroupSmooth( 0, 10 ); rhs_first->setGroupSmooth( 1, 20 ); rhs_first->setGroupSmooth( 2, 30 ); rhs_second->setGroupSmooth( 0, 10 ); rhs_second->setGroupSmooth( 1, 80 ); rhs_second->setGroupSmooth( 2, 30 ); QVERIFY_EQ( (uint8_t) 10, lhs->getGroupSmooth(0)); QVERIFY_EQ( (uint8_t) 20, lhs->getGroupSmooth(1)); QVERIFY_EQ( (uint8_t) 30, lhs->getGroupSmooth(2)); lhs->operationComplete( "Add groups" ); lhs->setGroupSmooth(1, 80 ); QVERIFY_EQ( (uint8_t) 10, lhs->getGroupSmooth(0)); QVERIFY_EQ( (uint8_t) 80, lhs->getGroupSmooth(1)); QVERIFY_EQ( (uint8_t) 30, lhs->getGroupSmooth(2)); lhs->operationComplete( "Set group smoothness" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testAddRemove() { local_ptr m = loadModelOrDie( "data/model_hidden_test.mm3d" ); m->unhideAll(); int grp = m->addGroup( "New Group" ); std::list lhs; // Should be empty QVERIFY( lhs == m->getGroupTriangles( grp ) ); addTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 0 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 2 ); addTriangleTest( lhs, m.get(), grp, 2 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 0 ); removeTriangleTest( lhs, m.get(), grp, 0 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 2 ); addTriangleTest( lhs, m.get(), grp, 2 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 0 ); removeTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 0 ); removeTriangleTest( lhs, m.get(), grp, 2 ); addTriangleTest( lhs, m.get(), grp, 0 ); addTriangleTest( lhs, m.get(), grp, 1 ); addTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 1 ); removeTriangleTest( lhs, m.get(), grp, 2 ); removeTriangleTest( lhs, m.get(), grp, 0 ); } void testAddSelected() { local_ptr m = newTestModel(); for ( int t = 0; t < 12; ++t ) { m->addVertex( (double) t, (double) t + 1, (double) t - 1 ); } for ( int t = 0; t < 10; ++t ) { m->addTriangle( t, t + 1, t + 2 ); } int grp = m->addGroup( "New Group" ); std::list lhs; // Should be empty QVERIFY( lhs == m->getGroupTriangles( grp ) ); lhs.clear(); lhs.push_back(0); lhs.push_back(1); lhs.push_back(2); lhs.push_back(3); lhs.push_back(4); lhs.push_back(5); lhs.push_back(6); lhs.push_back(7); lhs.push_back(8); lhs.push_back(9); checkGroupContents( lhs, m.get(), -1 ); // Test addSelectedToGroup() m->selectTriangle( 0 ); m->selectTriangle( 1 ); m->selectTriangle( 2 ); m->selectTriangle( 3 ); lhs.clear(); lhs.push_back( 0 ); lhs.push_back( 1 ); lhs.push_back( 2 ); lhs.push_back( 3 ); m->addSelectedToGroup( grp ); checkGroupContents( lhs, m.get(), grp ); lhs.clear(); lhs.push_back(4); lhs.push_back(5); lhs.push_back(6); lhs.push_back(7); lhs.push_back(8); lhs.push_back(9); checkGroupContents( lhs, m.get(), -1 ); m->unselectAll(); // Test addSelectedToGroup() does not duplicate triangles in group m->selectTriangle( 0 ); m->selectTriangle( 3 ); m->selectTriangle( 4 ); m->selectTriangle( 5 ); lhs.clear(); lhs.push_back( 0 ); lhs.push_back( 1 ); lhs.push_back( 2 ); lhs.push_back( 3 ); lhs.push_back( 4 ); lhs.push_back( 5 ); m->addSelectedToGroup( grp ); checkGroupContents( lhs, m.get(), grp ); lhs.clear(); lhs.push_back(6); lhs.push_back(7); lhs.push_back(8); lhs.push_back(9); checkGroupContents( lhs, m.get(), -1 ); m->unselectAll(); // Test setSelectedAsGroup(), including removal of triangles that // are not in the new set and inclusion of triangles that were // in the group originally. m->selectTriangle( 1 ); m->selectTriangle( 3 ); m->selectTriangle( 5 ); m->selectTriangle( 7 ); m->selectTriangle( 9 ); lhs.clear(); lhs.push_back( 1 ); lhs.push_back( 3 ); lhs.push_back( 5 ); lhs.push_back( 7 ); lhs.push_back( 9 ); m->setSelectedAsGroup( grp ); checkGroupContents( lhs, m.get(), grp ); lhs.clear(); lhs.push_back(0); lhs.push_back(2); lhs.push_back(4); lhs.push_back(6); lhs.push_back(8); checkGroupContents( lhs, m.get(), -1 ); m->unselectAll(); // Test that addSelectedToGroup removes triangles from another group int grp2 = m->addGroup( "New Group 2" ); m->selectTriangle( 3 ); m->selectTriangle( 5 ); m->addSelectedToGroup( grp2 ); lhs.clear(); lhs.push_back( 1 ); lhs.push_back( 7 ); lhs.push_back( 9 ); checkGroupContents( lhs, m.get(), grp ); lhs.clear(); lhs.push_back( 3 ); lhs.push_back( 5 ); checkGroupContents( lhs, m.get(), grp2 ); lhs.clear(); lhs.push_back(0); lhs.push_back(2); lhs.push_back(4); lhs.push_back(6); lhs.push_back(8); checkGroupContents( lhs, m.get(), -1 ); m->unselectAll(); // Test that setSelecedAsGroup removes triangles from another group m->selectTriangle( 1 ); m->setSelectedAsGroup( grp2 ); lhs.clear(); lhs.push_back( 1 ); checkGroupContents( lhs, m.get(), grp2 ); lhs.clear(); lhs.push_back( 7 ); lhs.push_back( 9 ); checkGroupContents( lhs, m.get(), grp ); lhs.clear(); lhs.push_back(0); lhs.push_back(2); lhs.push_back(3); lhs.push_back(4); lhs.push_back(5); lhs.push_back(6); lhs.push_back(8); checkGroupContents( lhs, m.get(), -1 ); m->unselectAll(); // FIXME test undo } // FIXME add tests: // deletion preserves triangle indices in group membership set // normal blending // smoothness // max angle // undo }; QTEST_MAIN(ModelGroupTest) #include "model_group_test.moc" mm3d-master/src/tests/libmm3d/model_init_test.cc000066400000000000000000000155161324021725400221700ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests initialization of the model compenents (inner classes). #include #include "test_common.h" #include "model.h" #include "texture.h" #include "local_array.h" class ModelInitTest : public QObject { Q_OBJECT private: void vertexIsInitialized( Model::Vertex * v ) { QVERIFY_TRUE( v->m_visible ); QVERIFY_FALSE( v->m_selected ); QVERIFY_FALSE( v->m_free ); QVERIFY( v->m_drawSource == v->m_coord ); } void triangleIsInitialized( Model::Triangle * t ) { QVERIFY_TRUE( t->m_visible ); QVERIFY_FALSE( t->m_selected ); QVERIFY_EQ( -1, t->m_projection ); // FIXME need fuzzy EQ for floats QVERIFY( t->m_flatSource == t->m_flatNormals ); QVERIFY( t->m_normalSource[0] == t->m_finalNormals[0] ); QVERIFY( t->m_normalSource[1] == t->m_finalNormals[1] ); QVERIFY( t->m_normalSource[2] == t->m_finalNormals[2] ); } void groupIsInitialized( Model::Group * g ) { QVERIFY_EQ( std::string(""), g->m_name ); QVERIFY_EQ( -1, g->m_materialIndex ); QVERIFY_EQ( (size_t) 0, g->m_triangleIndices.size() ); QVERIFY_EQ( (uint8_t) 255, g->m_smooth ); QVERIFY_EQ( (uint8_t) 89, g->m_angle ); QVERIFY_TRUE( g->m_visible ); QVERIFY_FALSE( g->m_selected ); } void materialIsInitialized( Model::Material * m ) { QVERIFY_EQ( std::string(""), m->m_name ); QVERIFY_EQ( Model::Material::MATTYPE_TEXTURE, m->m_type ); // FIXME need fuzzy EQ for floats QVERIFY_FALSE( m->m_sClamp ); QVERIFY_FALSE( m->m_tClamp ); QVERIFY_EQ( (GLuint) 0, m->m_texture ); QVERIFY_EQ( std::string(""), m->m_filename ); QVERIFY_EQ( std::string(""), m->m_alphaFilename ); QVERIFY_TRUE( NULL == m->m_textureData ); } private slots: // Many primitives are recycled. Test initial conditions, change conditions, // release, and re-get to make sure that the recyled primitives are properly // initialized. void testVertexInit() { Model::Vertex * v = Model::Vertex::get(); QVERIFY_EQ(1, Model::Vertex::allocated() ); QVERIFY_EQ(0, Model::Vertex::recycled() ); vertexIsInitialized( v ); v->m_visible = false; v->m_selected = true; v->m_free = true; v->m_drawSource = v->m_kfCoord; v->release(); QVERIFY_EQ(1, Model::Vertex::allocated() ); QVERIFY_EQ(1, Model::Vertex::recycled() ); v = Model::Vertex::get(); vertexIsInitialized( v ); QVERIFY_EQ(1, Model::Vertex::allocated() ); QVERIFY_EQ(0, Model::Vertex::recycled() ); v->release(); QVERIFY_EQ(1, Model::Vertex::allocated() ); QVERIFY_EQ(1, Model::Vertex::recycled() ); QVERIFY_EQ(1, Model::Vertex::flush() ) QVERIFY_EQ(0, Model::Vertex::allocated() ); QVERIFY_EQ(0, Model::Vertex::recycled() ); } void testTriangleInit() { Model::Triangle * t = Model::Triangle::get(); QVERIFY_EQ(1, Model::Triangle::allocated() ); QVERIFY_EQ(0, Model::Triangle::recycled() ); triangleIsInitialized( t ); t->m_visible = false; t->m_selected = true; t->m_projection = 7; t->m_flatSource = t->m_flatNormals; t->m_normalSource[0] = t->m_finalNormals[0]; t->m_normalSource[1] = t->m_finalNormals[1]; t->m_normalSource[2] = t->m_finalNormals[2]; t->release(); QVERIFY_EQ(1, Model::Triangle::allocated() ); QVERIFY_EQ(1, Model::Triangle::recycled() ); t = Model::Triangle::get(); triangleIsInitialized( t ); QVERIFY_EQ(1, Model::Triangle::allocated() ); QVERIFY_EQ(0, Model::Triangle::recycled() ); t->release(); QVERIFY_EQ(1, Model::Triangle::allocated() ); QVERIFY_EQ(1, Model::Triangle::recycled() ); QVERIFY_EQ(1, Model::Triangle::flush() ) QVERIFY_EQ(0, Model::Triangle::allocated() ); QVERIFY_EQ(0, Model::Triangle::recycled() ); } void testGroupInit() { Model::Group * g = Model::Group::get(); QVERIFY_EQ(1, Model::Group::allocated() ); QVERIFY_EQ(0, Model::Group::recycled() ); groupIsInitialized( g ); g->m_name = "dummy name"; g->m_materialIndex = 7; g->m_triangleIndices.insert(0); g->m_smooth = 8; g->m_angle = 9; g->m_visible = false; g->m_selected = true; g->release(); QVERIFY_EQ(1, Model::Group::allocated() ); QVERIFY_EQ(1, Model::Group::recycled() ); g = Model::Group::get(); groupIsInitialized( g ); QVERIFY_EQ(1, Model::Group::allocated() ); QVERIFY_EQ(0, Model::Group::recycled() ); g->release(); QVERIFY_EQ(1, Model::Group::allocated() ); QVERIFY_EQ(1, Model::Group::recycled() ); QVERIFY_EQ(1, Model::Group::flush() ) QVERIFY_EQ(0, Model::Group::allocated() ); QVERIFY_EQ(0, Model::Group::recycled() ); } void testMaterialInit() { Model::Material * m = Model::Material::get(); QVERIFY_EQ(1, Model::Material::allocated() ); QVERIFY_EQ(0, Model::Material::recycled() ); materialIsInitialized( m ); m->m_name = "dummy name"; m->m_type = Model::Material::MATTYPE_BLANK; // FIXME need fuzzy EQ for floats m->m_sClamp = true; m->m_tClamp = true; m->m_texture = 3; m->m_filename = "dummy file"; m->m_alphaFilename = "dummy alpha"; m->m_textureData = (Texture *) 100; m->release(); QVERIFY_EQ(1, Model::Material::allocated() ); QVERIFY_EQ(1, Model::Material::recycled() ); m = Model::Material::get(); materialIsInitialized( m ); QVERIFY_EQ(1, Model::Material::allocated() ); QVERIFY_EQ(0, Model::Material::recycled() ); m->release(); QVERIFY_EQ(1, Model::Material::allocated() ); QVERIFY_EQ(1, Model::Material::recycled() ); QVERIFY_EQ(1, Model::Material::flush() ) QVERIFY_EQ(0, Model::Material::allocated() ); QVERIFY_EQ(0, Model::Material::recycled() ); } // FIXME test other inits }; QTEST_MAIN(ModelInitTest) #include "model_init_test.moc" mm3d-master/src/tests/libmm3d/model_joint_test.cc000066400000000000000000000253331324021725400223460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests bone joint methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "log.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" #include class ModelJointTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); } void testAddBoneJoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_1->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); rhs_2->addBoneJoint( "Joint 4", 4, 4, 4, 0, 0, 1, 0 ); QVERIFY_EQ( 0, (int) lhs->getBoneJointCount() ); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Joint 2"), std::string(lhs->getBoneJointName(1)) ); lhs->operationComplete( "Add joints 1 and 2" ); lhs->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); lhs->addBoneJoint( "Joint 4", 4, 4, 4, 0, 0, 1, 0 ); QVERIFY_EQ( 4, (int) lhs->getBoneJointCount() ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Joint 2"), std::string(lhs->getBoneJointName(1)) ); QVERIFY_EQ( std::string("Joint 3"), std::string(lhs->getBoneJointName(2)) ); QVERIFY_EQ( std::string("Joint 4"), std::string(lhs->getBoneJointName(3)) ); lhs->operationComplete( "Add joints 3 and 4" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testDeleteBoneJoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_1->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); rhs_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 0 ); QVERIFY_EQ( 0, (int) lhs->getBoneJointCount() ); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); QVERIFY_EQ( 3, (int) lhs->getBoneJointCount() ); QVERIFY_EQ( 1, (int) lhs->getBoneJointParent(2) ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Joint 2"), std::string(lhs->getBoneJointName(1)) ); QVERIFY_EQ( std::string("Joint 3"), std::string(lhs->getBoneJointName(2)) ); lhs->operationComplete( "Add joints" ); lhs->deleteBoneJoint( 1 ); QVERIFY_EQ( 2, (int) lhs->getBoneJointCount() ); QVERIFY_EQ( 0, (int) lhs->getBoneJointParent(1) ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Joint 3"), std::string(lhs->getBoneJointName(1)) ); lhs->operationComplete( "Delete joint" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testRenameBoneJoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_1->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); rhs_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Renamed", 2, 2, 2, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); QVERIFY_EQ( 0, (int) lhs->getBoneJointCount() ); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); QVERIFY_EQ( 3, (int) lhs->getBoneJointCount() ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Joint 2"), std::string(lhs->getBoneJointName(1)) ); QVERIFY_EQ( std::string("Joint 3"), std::string(lhs->getBoneJointName(2)) ); lhs->operationComplete( "Add joints 1 and 2" ); lhs->setBoneJointName( 1, "Renamed" ); QVERIFY_EQ( std::string("Joint 1"), std::string(lhs->getBoneJointName(0)) ); QVERIFY_EQ( std::string("Renamed"), std::string(lhs->getBoneJointName(1)) ); QVERIFY_EQ( std::string("Joint 3"), std::string(lhs->getBoneJointName(2)) ); lhs->operationComplete( "Renamed bone joint" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testMoveBoneJoint() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_1->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); rhs_1->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); rhs_2->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 2", 4, 5, 6, 1, 0, 0, 0 ); rhs_2->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 2", 2, 2, 2, 1, 0, 0, 0 ); lhs->addBoneJoint( "Joint 3", 3, 3, 3, 0, 1, 0, 1 ); double expected[3] = { 0, 0, 0 }; double actual[3] = { 0, 0, 0 }; expected[0] = 1; expected[1] = 1; expected[2] = 1; lhs->getBoneJointCoords( 0, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 2; expected[1] = 2; expected[2] = 2; lhs->getBoneJointCoords( 1, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 3; expected[1] = 3; expected[2] = 3; lhs->getBoneJointCoords( 2, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); lhs->operationComplete( "Add joints 1 and 2" ); lhs->moveBoneJoint( 1, 4, 5, 6 ); expected[0] = 1; expected[1] = 1; expected[2] = 1; lhs->getBoneJointCoords( 0, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 4; expected[1] = 5; expected[2] = 6; lhs->getBoneJointCoords( 1, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 3; expected[1] = 3; expected[2] = 3; lhs->getBoneJointCoords( 2, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); lhs->operationComplete( "Move bone joint" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testGetLocalTranslation() { { local_ptr lhs = newTestModel(); lhs->addBoneJoint( "Joint 1", 1, 1, 1, 0, 0, 0 ); lhs->setupJoints(); const double trans[3] = { 1, 2, 3 }; lhs->setBoneJointTranslation( 0, trans ); lhs->setupJoints(); const double expected[3] = { 1, 2, 3 }; double actual[3] = { 0, 0, 0 }; lhs->getBoneJointCoords( 0, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); } { local_ptr lhs = newTestModel(); lhs->addBoneJoint( "Joint 1", 1, 2, 3, 0, 0, 0 ); lhs->addBoneJoint( "Joint 1", 2, 2, 2, 0, 0, 0, 0 ); lhs->setupJoints(); const double trans[3] = { 4, 3, 2 }; lhs->setBoneJointTranslation( 1, trans ); lhs->setupJoints(); const double expected[3] = { 5, 5, 5 }; double actual[3] = { 0, 0, 0 }; lhs->getBoneJointCoords( 1, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); } // FIXME rotation // FIXME multiple levels of joints // FIXME undo } // FIXME Tests to add: // x add joint // x delete joint // x rename joint // x get/set joint coords // x moveBoneJoint // x get joint parent // selection (parent joint selected) // hide/unhide // joint matrix is correct // Final // Absolute // Relative // - setBoneJointTranslation // setBoneJointRotation // get/setVertexBoneJoint // get/setPointBoneJoint // getBoneJointVertices // // FIXME Tests to add (in other files): // add/removeInfluence // Single // Multiple // Too many // getInfluenceList // getPrimaryInfluence // get/setInfluenceType // get/setInfluenceWeight // autoSetInfluences // calcRemainderWeight // Calculate weight // // FIXME Tests to add (in other files): // Skeletal animation // Setting keyframes directly // Modifying keyframes with transforms // Weight has proper effect with single joint // Weight has proper effect with multiple joints // Deleting a bone joint adjust influence indices }; QTEST_MAIN(ModelJointTest) #include "model_joint_test.moc" mm3d-master/src/tests/libmm3d/model_material_test.cc000066400000000000000000000531111324021725400230140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests grouping methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "tgatex.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" // FIXME centralize this Texture * loadTextureOrDie( TextureFilter * f, const char * filename ) { Texture * tex = new Texture; Texture::ErrorE err = f->readFile( tex, filename ); if ( err != Texture::ERROR_NONE ) { fprintf( stderr, "fatal: %s: %s\n", filename, Texture::errorToString( err ) ); delete tex; exit( -1 ); } return tex; } Texture * loadTgaOrDie( const char * filename ) { TgaTextureFilter f; return loadTextureOrDie( &f, filename ); } class ModelMaterialTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); } // FIXME add more tests void testAddColorMaterial() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Renamed" ); rhs_2->addColorMaterial( "Three" ); QVERIFY_EQ( 3, lhs->getTextureCount() ); QVERIFY_EQ( (int) Model::Material::MATTYPE_BLANK, (int) lhs->getMaterialType(1) ); QVERIFY_TRUE( NULL == lhs->getTextureData(1) ); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Two"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(2))); QVERIFY_EQ( 0, lhs->getMaterialByName("One")); QVERIFY_EQ( 1, lhs->getMaterialByName("Two")); QVERIFY_EQ( 2, lhs->getMaterialByName("Three")); QVERIFY_EQ( -1, lhs->getMaterialByName("Renamed")); lhs->operationComplete( "Add materials" ); lhs->setTextureName(1, "Renamed" ); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Renamed"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(2))); QVERIFY_EQ( 0, lhs->getMaterialByName("One")); QVERIFY_EQ( 1, lhs->getMaterialByName("Renamed")); QVERIFY_EQ( 2, lhs->getMaterialByName("Three")); QVERIFY_EQ( -1, lhs->getMaterialByName("Two")); lhs->operationComplete( "Set material name" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testAddTextureMaterial() { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr tex2 = loadTgaOrDie( "data/test_rgb_uncomp.tga" ); local_ptr tex3 = loadTgaOrDie( "data/test_rgba_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addTexture( tex1.get() ); lhs->addTexture( tex2.get() ); lhs->addTexture( tex3.get() ); rhs_1->addTexture( tex1.get() ); rhs_1->addTexture( tex2.get() ); rhs_1->addTexture( tex3.get() ); rhs_2->addTexture( tex1.get() ); rhs_2->addTexture( tex2.get() ); rhs_2->addTexture( tex3.get() ); rhs_2->setTextureName( 1, "Renamed" ); QVERIFY_EQ( 3, lhs->getTextureCount() ); QVERIFY_EQ( (int) Model::Material::MATTYPE_TEXTURE, (int) lhs->getMaterialType(1) ); QVERIFY_TRUE( tex2.get() == lhs->getTextureData(1) ); QVERIFY_EQ( std::string("data/test_rgb_uncomp.tga"), std::string(lhs->getTextureFilename(1)) ); QVERIFY_EQ( std::string("test_rgb_comp"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("test_rgb_uncomp"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("test_rgba_comp"), std::string(lhs->getTextureName(2))); QVERIFY_EQ( 0, lhs->getMaterialByName("test_rgb_comp")); QVERIFY_EQ( 1, lhs->getMaterialByName("test_rgb_uncomp")); QVERIFY_EQ( 2, lhs->getMaterialByName("test_rgba_comp")); QVERIFY_EQ( -1, lhs->getMaterialByName("Renamed")); lhs->operationComplete( "Add materials" ); lhs->setTextureName(1, "Renamed" ); QVERIFY_EQ( std::string("test_rgb_comp"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Renamed"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("test_rgba_comp"), std::string(lhs->getTextureName(2))); QVERIFY_EQ( 0, lhs->getMaterialByName("test_rgb_comp")); QVERIFY_EQ( 1, lhs->getMaterialByName("Renamed")); QVERIFY_EQ( 2, lhs->getMaterialByName("test_rgba_comp")); QVERIFY_EQ( -1, lhs->getMaterialByName("test_rgb_uncomp")); lhs->operationComplete( "Set material name" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testDeleteMaterial() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); lhs->addGroup( "One" ); lhs->addGroup( "Two" ); lhs->addGroup( "Three" ); lhs->setGroupTextureId( 0, 2 ); lhs->setGroupTextureId( 1, 1 ); lhs->setGroupTextureId( 2, 0 ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_1->addGroup( "One" ); rhs_1->addGroup( "Two" ); rhs_1->addGroup( "Three" ); rhs_1->setGroupTextureId( 0, 2 ); rhs_1->setGroupTextureId( 1, 1 ); rhs_1->setGroupTextureId( 2, 0 ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Three" ); rhs_2->addGroup( "One" ); rhs_2->addGroup( "Two" ); rhs_2->addGroup( "Three" ); rhs_2->setGroupTextureId( 0, 1 ); rhs_2->setGroupTextureId( 2, 0 ); QVERIFY_EQ( 3, lhs->getTextureCount() ); lhs->operationComplete( "Add materials and groups" ); lhs->deleteTexture( 1 ); QVERIFY_EQ( 2, lhs->getTextureCount() ); QVERIFY_EQ( 1, lhs->getGroupTextureId(0)); QVERIFY_EQ( -1, lhs->getGroupTextureId(1)); QVERIFY_EQ( 0, lhs->getGroupTextureId(2)); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(1))); lhs->operationComplete( "Delete material" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testAddRemoveTexture() { local_ptr tex1 = loadTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_1.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); rhs_2->setMaterialTexture( 1, tex1.get() ); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Two"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(2))); QVERIFY_EQ( (int) Model::Material::MATTYPE_BLANK, (int) lhs->getMaterialType(1) ); QVERIFY_TRUE( NULL == lhs->getTextureData(1) ); lhs->operationComplete( "Add materials" ); lhs->setMaterialTexture(1, tex1.get() ); QVERIFY_TRUE( tex1.get() == lhs->getTextureData(1) ); QVERIFY_EQ( std::string("data/test_rgb_comp.tga"), std::string(lhs->getTextureFilename(1)) ); QVERIFY_EQ( (int) Model::Material::MATTYPE_TEXTURE, (int) lhs->getMaterialType(1) ); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Two"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(2))); lhs->operationComplete( "Set material texture" ); lhs->removeMaterialTexture( 1 ); QVERIFY_EQ( (int) Model::Material::MATTYPE_BLANK, (int) lhs->getMaterialType(1) ); QVERIFY_TRUE( NULL == lhs->getTextureData(1) ); QVERIFY_EQ( std::string("One"), std::string(lhs->getTextureName(0))); QVERIFY_EQ( std::string("Two"), std::string(lhs->getTextureName(1))); QVERIFY_EQ( std::string("Three"), std::string(lhs->getTextureName(2))); lhs->operationComplete( "Set material texture" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testSetGroupMaterial() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); lhs->addGroup( "One" ); lhs->addGroup( "Two" ); lhs->addGroup( "Three" ); lhs->setGroupTextureId( 0, 0 ); lhs->setGroupTextureId( 1, 1 ); lhs->setGroupTextureId( 2, 2 ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_1->addGroup( "One" ); rhs_1->addGroup( "Two" ); rhs_1->addGroup( "Three" ); rhs_1->setGroupTextureId( 0, 0 ); rhs_1->setGroupTextureId( 1, 1 ); rhs_1->setGroupTextureId( 2, 2 ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); rhs_2->addGroup( "One" ); rhs_2->addGroup( "Two" ); rhs_2->addGroup( "Three" ); rhs_2->setGroupTextureId( 0, 2 ); rhs_2->setGroupTextureId( 2, 0 ); QVERIFY_EQ( 0, lhs->getGroupTextureId(0)); QVERIFY_EQ( 1, lhs->getGroupTextureId(1)); QVERIFY_EQ( 2, lhs->getGroupTextureId(2)); lhs->operationComplete( "Add materials and groups" ); lhs->setGroupTextureId( 0, 2 ); lhs->setGroupTextureId( 1, -1 ); lhs->setGroupTextureId( 2, 0 ); QVERIFY_EQ( 2, lhs->getGroupTextureId(0)); QVERIFY_EQ( -1, lhs->getGroupTextureId(1)); QVERIFY_EQ( 0, lhs->getGroupTextureId(2)); lhs->operationComplete( "Set group material ID" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetClamp() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); local_ptr rhs_3 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); rhs_list.push_back( rhs_3.get() ); QVERIFY_EQ( 0, lhs->getTextureCount() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); rhs_3->addColorMaterial( "One" ); rhs_3->addColorMaterial( "Two" ); rhs_3->addColorMaterial( "Three" ); lhs->setTextureSClamp( 1, false ); rhs_1->setTextureSClamp( 1, false ); rhs_2->setTextureSClamp( 1, true ); rhs_3->setTextureSClamp( 1, true ); lhs->setTextureTClamp( 1, false ); rhs_1->setTextureTClamp( 1, false ); rhs_2->setTextureTClamp( 1, false ); rhs_3->setTextureTClamp( 1, true ); QVERIFY_FALSE( lhs->getTextureSClamp(1) ); QVERIFY_FALSE( lhs->getTextureTClamp(1) ); lhs->operationComplete( "Add materials" ); lhs->setTextureSClamp( 1, true ); QVERIFY_TRUE( lhs->getTextureSClamp(1) ); QVERIFY_FALSE( lhs->getTextureTClamp(1) ); lhs->operationComplete( "Set material S clamp" ); lhs->setTextureTClamp( 1, true ); QVERIFY_TRUE( lhs->getTextureSClamp(1) ); QVERIFY_TRUE( lhs->getTextureTClamp(1) ); lhs->operationComplete( "Set material T clamp" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testSetAmbient() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); const float orig[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const float change[4] = { 0.2f, 0.4f, 0.6f, 0.8f }; float actual[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; lhs->setTextureAmbient( 1, orig ); rhs_1->setTextureAmbient( 1, orig ); rhs_2->setTextureAmbient( 1, change ); lhs->getTextureAmbient( 1, actual ); QVERIFY_ARRAY_EQ( orig, 4, actual, 4 ); lhs->operationComplete( "Add materials" ); lhs->setTextureAmbient( 1, change ); lhs->getTextureAmbient( 1, actual ); QVERIFY_ARRAY_EQ( change, 4, actual, 4 ); lhs->operationComplete( "Set material ambient" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetDiffuse() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); const float orig[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const float change[4] = { 0.2f, 0.4f, 0.6f, 0.8f }; float actual[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; lhs->setTextureDiffuse( 1, orig ); rhs_1->setTextureDiffuse( 1, orig ); rhs_2->setTextureDiffuse( 1, change ); lhs->getTextureDiffuse( 1, actual ); QVERIFY_ARRAY_EQ( orig, 4, actual, 4 ); lhs->operationComplete( "Add materials" ); lhs->setTextureDiffuse( 1, change ); lhs->getTextureDiffuse( 1, actual ); QVERIFY_ARRAY_EQ( change, 4, actual, 4 ); lhs->operationComplete( "Set material diffuse" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetEmissive() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); const float orig[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const float change[4] = { 0.2f, 0.4f, 0.6f, 0.8f }; float actual[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; lhs->setTextureEmissive( 1, orig ); rhs_1->setTextureEmissive( 1, orig ); rhs_2->setTextureEmissive( 1, change ); lhs->getTextureEmissive( 1, actual ); QVERIFY_ARRAY_EQ( orig, 4, actual, 4 ); lhs->operationComplete( "Add materials" ); lhs->setTextureEmissive( 1, change ); lhs->getTextureEmissive( 1, actual ); QVERIFY_ARRAY_EQ( change, 4, actual, 4 ); lhs->operationComplete( "Set material emissive" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetSpecular() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); const float orig[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; const float change[4] = { 0.2f, 0.4f, 0.6f, 0.8f }; float actual[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; lhs->setTextureSpecular( 1, orig ); rhs_1->setTextureSpecular( 1, orig ); rhs_2->setTextureSpecular( 1, change ); lhs->getTextureSpecular( 1, actual ); QVERIFY_ARRAY_EQ( orig, 4, actual, 4 ); lhs->operationComplete( "Add materials" ); lhs->setTextureSpecular( 1, change ); lhs->getTextureSpecular( 1, actual ); QVERIFY_ARRAY_EQ( change, 4, actual, 4 ); lhs->operationComplete( "Set material specular" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetShininess() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_1 = newTestModel(); local_ptr rhs_2 = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_1.get() ); rhs_list.push_back( rhs_2.get() ); lhs->addColorMaterial( "One" ); lhs->addColorMaterial( "Two" ); lhs->addColorMaterial( "Three" ); rhs_1->addColorMaterial( "One" ); rhs_1->addColorMaterial( "Two" ); rhs_1->addColorMaterial( "Three" ); rhs_2->addColorMaterial( "One" ); rhs_2->addColorMaterial( "Two" ); rhs_2->addColorMaterial( "Three" ); const float orig = 1.0f; const float change = 0.5f; float actual = 1.0f; lhs->setTextureShininess( 1, orig ); rhs_1->setTextureShininess( 1, orig ); rhs_2->setTextureShininess( 1, change ); lhs->getTextureShininess( 1, actual ); QVERIFY_EQ( orig, actual ); lhs->operationComplete( "Add materials" ); lhs->setTextureShininess( 1, change ); lhs->getTextureShininess( 1, actual ); QVERIFY_EQ( change, actual ); lhs->operationComplete( "Set material shininess" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } // FIXME in another file: // rendering // type // lighting // clamp // load textures // invalidate textures }; QTEST_MAIN(ModelMaterialTest) #include "model_material_test.moc" mm3d-master/src/tests/libmm3d/model_select_test.cc000066400000000000000000000033121324021725400224730ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests selection methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" class ModelSelectTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); } // FIXME add some real tests void testConnectedWithHidden() { local_ptr m = loadModelOrDie( "data/model_hidden_test.mm3d" ); m->setSelectionMode( Model::SelectConnected ); Matrix mat; mat.loadIdentity(); m->selectInVolumeMatrix( mat, -1.0, -1.0, 1.0, 1.0 ); QVERIFY_EQ( 36, (int) m->getSelectedTriangleCount() ); } }; QTEST_MAIN(ModelSelectTest) #include "model_select_test.moc" mm3d-master/src/tests/libmm3d/model_test.cc000066400000000000000000000077061324021725400211470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the primary functionality of libmm3d/model.h // Some features of the Model class are tested by other test files. // TODO General: // * Observer add/remove/receive changes // * Error code to failure mapping // * Push/pop errors // * diff (equivalent) // * get/set filename // * get/set export file // * get/set filter-specific error // * drawing (right...) // * texture/context loading/removing, deleteGLTextures // * Invalidate textures // * Texture data compare fuzziness // * add/delete/get format data // * background images get/set image/scale/center // * meta data get(by name/index)/set/removeLast(internal)/clear // * merge models // * merge animations // * boolean operations // * render options (joint mode, projections, canvas draw mode) // // TODO Geometry: // * Deletions // - Delete selected // - Force add/delete // x Remove oprhaned vertices (and not free vertices) // x Remove flattened triangles // * Set/get primitive properties // x Vertices // x Faces // x Groups // x Materials // - Bone Joints // - Points // - Texture Projections (seam/up/range/scale/type/rotation(misnamed arg)) // - Moving // - Hiding // x Hide selected // - Hide unselected // x Unhide all // * Selection // - Volume selection // - Selection mode // - Interaction with visibility // - Selection test // - Invert selection // - Selection difference // - Joint parent selection // - Select primitives from other primitives // - getSelected{PRIMITIVE} list // * Bounding region // * Transforms // - Translate // - Rotate // - Apply Matrix (w/undoable or not) // * Subdivide/unsubdivide // * Simplify mesh // * Normals/cosToPoint // * Anim Normals // * BSP Tree generation // * Grouping and group properties // * Skeletal structure // * Bone joint matrices // * Bone joint assignment // * Bone joint weighting calculations // * Bone primary influence calculations // * Auto assign bone joint // * getBoneVector // * Position accessors // * Texture coordinates // * Projection mapping // * Local matrix // // TODO Undo: // * Undo works on everything // * Redo works on everything // x Undo current // * Enable/disable works // x Size calculation works // x Limits work // x Atomic operation names // x canUndo/canRedo // * setUndoEnabled // x Save interaction (getSaved/setSaved) // x undoRelease/redoRelease // // TODO Animation: // * Add/remove animation // * Properties (name, fps, etc.) // * Add/remove animation frames // * Copy/join/split/merge/convert // * Move animation // * Setting animation time/frame/none // * Looping // * Set/get animation frame data // - Keyframe // - Mesh deformation // - Clear // * Interpolation // #include #include "test_common.h" #include "model.h" #include "texture.h" #include "local_array.h" class ModelTest : public QObject { Q_OBJECT private: private slots: void testSomething() { } }; QTEST_MAIN(ModelTest) #include "model_test.moc" mm3d-master/src/tests/libmm3d/model_triangle_test.cc000066400000000000000000000776341324021725400230430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests triangle methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "log.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" #include class ModelTriangleTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); } void testSelectTriangle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_unselected.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 2, 1, 0 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_unselected->addTriangle( 0, 1, 2 ); rhs_unselected->addTriangle( 2, 1, 0 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->addTriangle( 2, 1, 0 ); rhs_selected->selectTriangle( 1 ); lhs->operationComplete( "Add triangles" ); lhs->selectTriangle( 1 ); QVERIFY_FALSE( lhs->isTriangleSelected( 0 ) ); QVERIFY_TRUE( lhs->isTriangleSelected( 1 ) ); lhs->operationComplete( "Select triangle" ); lhs->unselectTriangle( 1 ); QVERIFY_FALSE( lhs->isTriangleSelected( 0 ) ); QVERIFY_FALSE( lhs->isTriangleSelected( 1 ) ); lhs->operationComplete( "Unselect triangle" ); lhs->selectTriangle( 1 ); QVERIFY_FALSE( lhs->isTriangleSelected( 0 ) ); QVERIFY_TRUE( lhs->isTriangleSelected( 1 ) ); lhs->operationComplete( "Select triangle" ); lhs->unselectAll(); QVERIFY_FALSE( lhs->isTriangleSelected( 0 ) ); QVERIFY_FALSE( lhs->isTriangleSelected( 1 ) ); lhs->operationComplete( "Unselect all" ); checkUndoRedo( 5, lhs.get(), rhs_list ); } void testGetSelectedList() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 1, 2, 0 ); lhs->addTriangle( 2, 0, 1 ); lhs->addTriangle( 2, 1, 0 ); lhs->addTriangle( 1, 0, 2 ); lhs->addTriangle( 0, 2, 1 ); list tris; list::const_iterator it; lhs->getSelectedTriangles( tris ); QVERIFY(tris.begin() == tris.end()); QVERIFY_EQ( 0, (int) lhs->getSelectedTriangleCount() ); lhs->selectTriangle( 0 ); QVERIFY_EQ( 1, (int) lhs->getSelectedTriangleCount() ); lhs->selectTriangle( 5 ); QVERIFY_EQ( 2, (int) lhs->getSelectedTriangleCount() ); lhs->selectTriangle( 3 ); QVERIFY_EQ( 3, (int) lhs->getSelectedTriangleCount() ); lhs->selectTriangle( 1 ); QVERIFY_EQ( 4, (int) lhs->getSelectedTriangleCount() ); lhs->getSelectedTriangles( tris ); QVERIFY(tris.begin() != tris.end()); it = tris.begin(); QVERIFY(it != tris.end()); QVERIFY_EQ(0, *it ); ++it; QVERIFY(it != tris.end()); QVERIFY_EQ(1, *it ); ++it; QVERIFY(it != tris.end()); QVERIFY_EQ(3, *it ); ++it; QVERIFY(it != tris.end()); QVERIFY_EQ(5, *it ); ++it; QVERIFY(it == tris.end()); } // Tests that a selected triangle is deleted, but shared vertices // are not. void testDeleteSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); local_ptr rhs_deleted = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_deleted.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 2, 0, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 3, 2, 1 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_unselected->addVertex( 2, 0, 0 ); rhs_unselected->addTriangle( 0, 1, 2 ); rhs_unselected->addTriangle( 3, 2, 1 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addVertex( 2, 0, 0 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->addTriangle( 3, 2, 1 ); rhs_selected->selectTriangle( 0 ); rhs_deleted->addVertex( 1, 0, 0 ); rhs_deleted->addVertex( 1, 1, 0 ); rhs_deleted->addVertex( 2, 0, 0 ); rhs_deleted->addTriangle( 2, 1, 0 ); lhs->operationComplete( "Add triangles" ); lhs->selectTriangle( 0 ); lhs->operationComplete( "Select triangle" ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } // Tests that vertices are deleted when no triangles are using them. void testDeleteSelectedNoFree() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_unselected->addTriangle( 0, 1, 2 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->selectTriangle( 0 ); lhs->operationComplete( "Add triangles" ); lhs->selectTriangle( 0 ); lhs->operationComplete( "Select triangle" ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } // Tests that vertices are not deleted if they are marked free void testDeleteSelectedFree() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); local_ptr rhs_deleted = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_deleted.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->setVertexFree( 1, true ); lhs->addTriangle( 0, 1, 2 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_unselected->setVertexFree( 1, true ); rhs_unselected->addTriangle( 0, 1, 2 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->setVertexFree( 1, true ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->selectTriangle( 0 ); rhs_deleted->addVertex( 1, 0, 0 ); rhs_deleted->setVertexFree( 0, true ); lhs->operationComplete( "Add triangles" ); lhs->selectTriangle( 0 ); lhs->operationComplete( "Select triangle" ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testHideTriangle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); local_ptr rhs_hidden = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_hidden.get() ); rhs_list.push_back( rhs_unselected.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 2, 0, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 1, 2, 3 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_unselected->addVertex( 2, 0, 0 ); rhs_unselected->addTriangle( 0, 1, 2 ); rhs_unselected->addTriangle( 1, 2, 3 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addVertex( 2, 0, 0 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->addTriangle( 1, 2, 3 ); rhs_selected->selectTriangle( 1 ); rhs_hidden->addVertex( 0, 0, 0 ); rhs_hidden->addVertex( 1, 0, 0 ); rhs_hidden->addVertex( 1, 1, 0 ); rhs_hidden->addVertex( 2, 0, 0 ); rhs_hidden->addTriangle( 0, 1, 2 ); rhs_hidden->addTriangle( 1, 2, 3 ); rhs_hidden->hideTriangle( 1 ); rhs_hidden->hideVertex( 3 ); // Have to do this directly lhs->operationComplete( "Add triangles" ); lhs->selectTriangle( 1 ); QVERIFY_TRUE( lhs->isTriangleVisible( 0 ) ); QVERIFY_TRUE( lhs->isTriangleVisible( 1 ) ); lhs->operationComplete( "Select triangle" ); lhs->hideSelected(); QVERIFY_TRUE( lhs->isTriangleVisible( 0 ) ); QVERIFY_FALSE( lhs->isTriangleVisible( 1 ) ); lhs->operationComplete( "Hide selected" ); lhs->unhideAll(); QVERIFY_TRUE( lhs->isTriangleVisible( 0 ) ); QVERIFY_TRUE( lhs->isTriangleVisible( 1 ) ); lhs->operationComplete( "Unhide all" ); checkUndoRedo( 4, lhs.get(), rhs_list ); } void testDeleteTriangle() { // deleteTriangle does not delete orphaned vertices (and these // aren't orphaned anyway) local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); local_ptr rhs_deleted = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); rhs_list.push_back( rhs_deleted.get() ); QVERIFY_EQ( 0, (int) lhs->getTriangleCount() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); QVERIFY_EQ( 1, (int) lhs->getTriangleCount() ); lhs->addTriangle( 2, 1, 0 ); QVERIFY_EQ( 2, (int) lhs->getTriangleCount() ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); rhs_full->addTriangle( 0, 1, 2 ); rhs_full->addTriangle( 2, 1, 0 ); rhs_deleted->addVertex( 0, 0, 0 ); rhs_deleted->addVertex( 1, 0, 0 ); rhs_deleted->addVertex( 1, 1, 0 ); rhs_deleted->addTriangle( 2, 1, 0 ); lhs->operationComplete( "Add triangles" ); lhs->deleteTriangle( 0 ); QVERIFY_EQ( 1, (int) lhs->getTriangleCount() ); lhs->operationComplete( "Delete triangle" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } // Tests that a triangle with an edge that uses the same vertex for // both end points is deleted by deleteFlattenedTriangles() void testDeleteFlattened() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); local_ptr rhs_deleted = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); rhs_list.push_back( rhs_deleted.get() ); QVERIFY_EQ( 0, (int) lhs->getTriangleCount() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 1, 2, 2 ); lhs->addTriangle( 0, 0, 2 ); lhs->addTriangle( 1, 0, 1 ); lhs->addTriangle( 1, 1, 1 ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); rhs_full->addTriangle( 0, 1, 2 ); rhs_full->addTriangle( 1, 2, 2 ); rhs_full->addTriangle( 0, 0, 2 ); rhs_full->addTriangle( 1, 0, 1 ); rhs_full->addTriangle( 1, 1, 1 ); rhs_deleted->addVertex( 0, 0, 0 ); rhs_deleted->addVertex( 1, 0, 0 ); rhs_deleted->addVertex( 1, 1, 0 ); rhs_deleted->addTriangle( 0, 1, 2 ); lhs->operationComplete( "Add triangles" ); lhs->deleteFlattenedTriangles(); lhs->operationComplete( "Delete flattened" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetVertices() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_front = newTestModel(); local_ptr rhs_back = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_front.get() ); rhs_list.push_back( rhs_back.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); rhs_front->addVertex( 0, 0, 0 ); rhs_front->addVertex( 1, 0, 0 ); rhs_front->addVertex( 1, 1, 0 ); rhs_front->addTriangle( 0, 1, 2 ); rhs_back->addVertex( 0, 0, 0 ); rhs_back->addVertex( 1, 0, 0 ); rhs_back->addVertex( 1, 1, 0 ); rhs_back->addTriangle( 2, 1, 0 ); lhs->operationComplete( "Add triangles" ); unsigned int vert[3]; QVERIFY_EQ( 0, lhs->getTriangleVertex( 0, 0 ) ); QVERIFY_EQ( 1, lhs->getTriangleVertex( 0, 1 ) ); QVERIFY_EQ( 2, lhs->getTriangleVertex( 0, 2 ) ); lhs->getTriangleVertices( 0, vert[0], vert[1], vert[2] ); QVERIFY_EQ( 0, (int) vert[0] ); QVERIFY_EQ( 1, (int) vert[1] ); QVERIFY_EQ( 2, (int) vert[2] ); lhs->setTriangleVertices( 0, 2, 1, 0 ); QVERIFY_EQ( 2, lhs->getTriangleVertex( 0, 0 ) ); QVERIFY_EQ( 1, lhs->getTriangleVertex( 0, 1 ) ); QVERIFY_EQ( 0, lhs->getTriangleVertex( 0, 2 ) ); lhs->getTriangleVertices( 0, vert[0], vert[1], vert[2] ); QVERIFY_EQ( 2, (int) vert[0] ); QVERIFY_EQ( 1, (int) vert[1] ); QVERIFY_EQ( 0, (int) vert[2] ); lhs->operationComplete( "Set vertices" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testTriangleTextureCoords() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unassigned = newTestModel(); local_ptr rhs_assigned = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unassigned.get() ); rhs_list.push_back( rhs_assigned.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 1, 2, 3 ); rhs_unassigned->addVertex( 0, 0, 0 ); rhs_unassigned->addVertex( 1, 0, 0 ); rhs_unassigned->addVertex( 1, 1, 0 ); rhs_unassigned->addVertex( 0, 1, 0 ); rhs_unassigned->addTriangle( 0, 1, 2 ); rhs_unassigned->addTriangle( 1, 2, 3 ); rhs_assigned->addVertex( 0, 0, 0 ); rhs_assigned->addVertex( 1, 0, 0 ); rhs_assigned->addVertex( 1, 1, 0 ); rhs_assigned->addVertex( 0, 1, 0 ); rhs_assigned->addTriangle( 0, 1, 2 ); rhs_assigned->addTriangle( 1, 2, 3 ); rhs_assigned->setTextureCoords( 0, 0, 0.0, 1.0 ); rhs_assigned->setTextureCoords( 0, 1, 0.1, 0.9 ); rhs_assigned->setTextureCoords( 0, 2, 0.2, 0.8 ); rhs_assigned->setTextureCoords( 1, 0, 0.5, 0.5 ); rhs_assigned->setTextureCoords( 1, 1, 0.6, 0.4 ); rhs_assigned->setTextureCoords( 1, 2, 0.7, 0.3 ); lhs->operationComplete( "Add triangle and projections" ); lhs->setTextureCoords( 0, 0, 0.0, 1.0 ); lhs->setTextureCoords( 0, 1, 0.1, 0.9 ); lhs->setTextureCoords( 0, 2, 0.2, 0.8 ); lhs->setTextureCoords( 1, 0, 0.5, 0.5 ); lhs->setTextureCoords( 1, 1, 0.6, 0.4 ); lhs->setTextureCoords( 1, 2, 0.7, 0.3 ); float s = 0.0; float t = 0.0; lhs->getTextureCoords( 0, 0, s, t ); QVERIFY_EQ( 0.0f, s ); QVERIFY_EQ( 1.0f, t ); lhs->getTextureCoords( 0, 1, s, t ); QVERIFY_EQ( 0.1f, s ); QVERIFY_EQ( 0.9f, t ); lhs->getTextureCoords( 0, 2, s, t ); QVERIFY_EQ( 0.2f, s ); QVERIFY_EQ( 0.8f, t ); lhs->getTextureCoords( 1, 0, s, t ); QVERIFY_EQ( 0.5f, s ); QVERIFY_EQ( 0.5f, t ); lhs->getTextureCoords( 1, 1, s, t ); QVERIFY_EQ( 0.6f, s ); QVERIFY_EQ( 0.4f, t ); lhs->getTextureCoords( 1, 2, s, t ); QVERIFY_EQ( 0.7f, s ); QVERIFY_EQ( 0.3f, t ); lhs->operationComplete( "Set texture coords" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testTriangleProjection() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_none = newTestModel(); local_ptr rhs_first = newTestModel(); local_ptr rhs_second = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_none.get() ); rhs_list.push_back( rhs_first.get() ); rhs_list.push_back( rhs_second.get() ); rhs_list.push_back( rhs_none.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->addProjection( "first", 0, 0, 0, Model::TPT_Plane ); lhs->addProjection( "second", 1, 1, 1, Model::TPT_Plane ); rhs_none->addVertex( 0, 0, 0 ); rhs_none->addVertex( 1, 0, 0 ); rhs_none->addVertex( 1, 1, 0 ); rhs_none->addTriangle( 0, 1, 2 ); rhs_none->addProjection( "first", 0, 0, 0, Model::TPT_Plane ); rhs_none->addProjection( "second", 1, 1, 1, Model::TPT_Plane ); rhs_first->addVertex( 0, 0, 0 ); rhs_first->addVertex( 1, 0, 0 ); rhs_first->addVertex( 1, 1, 0 ); rhs_first->addTriangle( 0, 1, 2 ); rhs_first->addProjection( "first", 0, 0, 0, Model::TPT_Plane ); rhs_first->addProjection( "second", 1, 1, 1, Model::TPT_Plane ); rhs_first->setTriangleProjection( 0, 0 ); rhs_second->addVertex( 0, 0, 0 ); rhs_second->addVertex( 1, 0, 0 ); rhs_second->addVertex( 1, 1, 0 ); rhs_second->addTriangle( 0, 1, 2 ); rhs_second->addProjection( "first", 0, 0, 0, Model::TPT_Plane ); rhs_second->addProjection( "second", 1, 1, 1, Model::TPT_Plane ); rhs_second->setTriangleProjection( 0, 1 ); QVERIFY_EQ( -1, lhs->getTriangleProjection( 0 ) ); lhs->operationComplete( "Add triangle and projections" ); lhs->setTriangleProjection( 0, 0 ); QVERIFY_EQ( 0, lhs->getTriangleProjection( 0 ) ); lhs->operationComplete( "Set first projection" ); lhs->setTriangleProjection( 0, 1 ); QVERIFY_EQ( 1, lhs->getTriangleProjection( 0 ) ); lhs->operationComplete( "Set second projection" ); lhs->setTriangleProjection( 0, -1 ); QVERIFY_EQ( -1, lhs->getTriangleProjection( 0 ) ); lhs->operationComplete( "Set no projection" ); checkUndoRedo( 4, lhs.get(), rhs_list ); } void testFlatNormal() { // +X { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 0, 1, 0 ); lhs->addVertex( 0, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { 1.0f, 0.0f, 0.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } // -X { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 0, 1, 1 ); lhs->addVertex( 0, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { -1.0f, 0.0f, 0.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } // +Y { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { 0.0f, 1.0f, 0.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } // -Y { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 0, 0, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { 0.0f, -1.0f, 0.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } // +Z { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { 0.0f, 0.0f, 1.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } // -Z { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addTriangle( 0, 1, 2 ); lhs->calculateNormals(); float expected[3] = { 0.0f, 0.0f, -1.0f }; float norm[3]; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 1, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); memset( norm, 0, sizeof(norm) ); lhs->getNormal( 0, 2, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); } } void testInvertNormals() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_front = newTestModel(); local_ptr rhs_back = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_front.get() ); rhs_list.push_back( rhs_back.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 0, 1, 0 ); lhs->addVertex( 0, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); rhs_front->addVertex( 0, 0, 0 ); rhs_front->addVertex( 0, 1, 0 ); rhs_front->addVertex( 0, 1, 1 ); rhs_front->addTriangle( 0, 1, 2 ); rhs_back->addVertex( 0, 0, 0 ); rhs_back->addVertex( 0, 1, 0 ); rhs_back->addVertex( 0, 1, 1 ); rhs_back->addTriangle( 2, 1, 0 ); lhs->operationComplete( "Add triangle" ); float norm[3]; float expected[3] = { 1.0f, 0.0f, 0.0f }; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( expected, 3, norm, 3 ); lhs->invertNormals( 0 ); lhs->operationComplete( "Invert normals" ); float inverted[3] = { -1.0f, 0.0f, 0.0f }; lhs->getFlatNormal( 0, norm ); QVERIFY_ARRAY_EQ( inverted, 3, norm, 3 ); // FIXME want to test that 0 and 2 swap texture coords? float s = 0; float t = 0; lhs->getTextureCoords( 0, 0, s, t ); rhs_back->setTextureCoords( 0, 0, s, t ); lhs->getTextureCoords( 0, 1, s, t ); rhs_back->setTextureCoords( 0, 1, s, t ); lhs->getTextureCoords( 0, 2, s, t ); rhs_back->setTextureCoords( 0, 2, s, t ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testFaceOutNone() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); // Nothing in front, must face out QVERIFY_FALSE( lhs->triangleFacesIn( 0 ) ); } void testFaceInBack() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 3, 4, 5 ); QVERIFY_TRUE( lhs->triangleFacesIn( 0 ) ); QVERIFY_FALSE( lhs->triangleFacesIn( 1 ) ); } void testFaceInFront() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 5, 4, 3 ); QVERIFY_TRUE( lhs->triangleFacesIn( 0 ) ); QVERIFY_TRUE( lhs->triangleFacesIn( 1 ) ); } void testFaceOutTwo() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 0, 0, 2 ); lhs->addVertex( 1, 0, 2 ); lhs->addVertex( 1, 1, 2 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 3, 4, 5 ); lhs->addTriangle( 6, 7, 8 ); // Hits an even number of triangles, must face out QVERIFY_FALSE( lhs->triangleFacesIn( 0 ) ); } void testFaceOutBack() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addTriangle( 2, 1, 0 ); lhs->addTriangle( 3, 4, 5 ); QVERIFY_FALSE( lhs->triangleFacesIn( 0 ) ); QVERIFY_FALSE( lhs->triangleFacesIn( 1 ) ); } void testFaceInOneEdge() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 0, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 5, 4, 3 ); QVERIFY_FALSE( lhs->triangleFacesIn( 0 ) ); } void testFaceInTwoEdges() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 0, 1, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 5, 4, 3 ); lhs->addTriangle( 5, 6, 4 ); // Hits two edges, must be inside QVERIFY_TRUE( lhs->triangleFacesIn( 0 ) ); } void testFaceOutFrontAndBack() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 0, 1 ); lhs->addVertex( 1, 0, 1 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 0, 0, -1 ); lhs->addVertex( 1, 0, -1 ); lhs->addVertex( 1, 1, -1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 3, 4, 5 ); lhs->addTriangle( 6, 7, 8 ); // Hits one in front and one in back. Something screwy is going on. // Can't be certain it is facing inward. QVERIFY_FALSE( lhs->triangleFacesIn( 0 ) ); } // FIXME Tests to add // // Triangle tests: // cosToPoint // subdivide // For each triangle // if contains one original point // contains no other original points // vector to other points is unchanged // else // one triangle contains three unique non-original points // normal matches original triangle // Triangle count and welded vertex count are correct // // FIXME test in other files: // simplify mesh? // select vertices from triangles // Group normal blending }; QTEST_MAIN(ModelTriangleTest) #include "model_triangle_test.moc" mm3d-master/src/tests/libmm3d/model_vertex_test.cc000066400000000000000000000445371324021725400225470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests vertex methods in the Model class. #include #include "test_common.h" #include "model.h" #include "texture.h" #include "log.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" #include class ModelVertexTest : public QObject { Q_OBJECT private: private slots: void initTestCase() { log_enable_debug( false ); } void testSelectVertex() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_unselected = newTestModel(); local_ptr rhs_selected = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_unselected.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_unselected.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); rhs_unselected->addVertex( 0, 0, 0 ); rhs_unselected->addVertex( 1, 0, 0 ); rhs_unselected->addVertex( 1, 1, 0 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->selectVertex( 1 ); lhs->operationComplete( "Add vertices" ); lhs->selectVertex( 1 ); QVERIFY_FALSE( lhs->isVertexSelected( 0 ) ); QVERIFY_TRUE( lhs->isVertexSelected( 1 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 2 ) ); lhs->operationComplete( "Select vertex" ); lhs->unselectVertex( 1 ); QVERIFY_FALSE( lhs->isVertexSelected( 0 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 1 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 2 ) ); lhs->operationComplete( "Unselect vertex" ); lhs->selectVertex( 1 ); QVERIFY_FALSE( lhs->isVertexSelected( 0 ) ); QVERIFY_TRUE( lhs->isVertexSelected( 1 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 2 ) ); lhs->operationComplete( "Select vertex" ); lhs->unselectAll(); QVERIFY_FALSE( lhs->isVertexSelected( 0 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 1 ) ); QVERIFY_FALSE( lhs->isVertexSelected( 2 ) ); lhs->operationComplete( "Unselect all" ); checkUndoRedo( 5, lhs.get(), rhs_list ); } void testGetSelectedList() { local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 1, 1, 1 ); lhs->addVertex( 0, 1, 1 ); lhs->addVertex( 0, 0, 1 ); std::list verts; std::list::const_iterator it; lhs->getSelectedVertices( verts ); QVERIFY(verts.begin() == verts.end()); QVERIFY_EQ( 0, (int) lhs->getSelectedVertexCount() ); lhs->selectVertex( 0 ); QVERIFY_EQ( 1, (int) lhs->getSelectedVertexCount() ); lhs->selectVertex( 5 ); QVERIFY_EQ( 2, (int) lhs->getSelectedVertexCount() ); lhs->selectVertex( 3 ); QVERIFY_EQ( 3, (int) lhs->getSelectedVertexCount() ); lhs->selectVertex( 2 ); QVERIFY_EQ( 4, (int) lhs->getSelectedVertexCount() ); lhs->getSelectedVertices( verts ); QVERIFY(verts.begin() != verts.end()); it = verts.begin(); QVERIFY(it != verts.end()); QVERIFY_EQ(0, *it ); ++it; QVERIFY(it != verts.end()); QVERIFY_EQ(2, *it ); ++it; QVERIFY(it != verts.end()); QVERIFY_EQ(3, *it ); ++it; QVERIFY(it != verts.end()); QVERIFY_EQ(5, *it ); ++it; QVERIFY(it == verts.end()); } void testMoveVertex() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_orig = newTestModel(); local_ptr rhs_moved = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_orig.get() ); rhs_list.push_back( rhs_moved.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); rhs_orig->addVertex( 0, 0, 0 ); rhs_orig->addVertex( 1, 0, 0 ); rhs_orig->addVertex( 1, 1, 0 ); rhs_moved->addVertex( 3, 4, 5 ); rhs_moved->addVertex( 2, 1, 0 ); rhs_moved->addVertex( -3, -4, -5 ); double expected[3] = { 0, 0, 0 }; double actual[3] = { 0, 0, 0 }; expected[0] = 0; expected[1] = 0; expected[2] = 0; lhs->getVertexCoords( 0, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 1; expected[1] = 0; expected[2] = 0; lhs->getVertexCoords( 1, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 1; expected[1] = 1; expected[2] = 0; lhs->getVertexCoords( 2, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); lhs->operationComplete( "Add vertices" ); lhs->moveVertex( 0, 3, 4, 5 ); lhs->moveVertex( 1, 2, 1, 0 ); lhs->moveVertex( 2, -3, -4, -5 ); expected[0] = 3; expected[1] = 4; expected[2] = 5; lhs->getVertexCoords( 0, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = 2; expected[1] = 1; expected[2] = 0; lhs->getVertexCoords( 1, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); expected[0] = -3; expected[1] = -4; expected[2] = -5; lhs->getVertexCoords( 2, actual ); QVERIFY_ARRAY_EQ( expected, 3, actual, 3 ); lhs->operationComplete( "Move vertices" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testSetFree() { // setVertexFree is not an undoable operation local_ptr lhs = newTestModel(); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); QVERIFY_FALSE( lhs->isVertexFree( 0 ) ); QVERIFY_FALSE( lhs->isVertexFree( 1 ) ); QVERIFY_FALSE( lhs->isVertexFree( 2 ) ); lhs->setVertexFree( 1, true ); QVERIFY_FALSE( lhs->isVertexFree( 0 ) ); QVERIFY_TRUE( lhs->isVertexFree( 1 ) ); QVERIFY_FALSE( lhs->isVertexFree( 2 ) ); lhs->setVertexFree( 1, false ); QVERIFY_FALSE( lhs->isVertexFree( 0 ) ); QVERIFY_FALSE( lhs->isVertexFree( 1 ) ); QVERIFY_FALSE( lhs->isVertexFree( 2 ) ); } void testDeleteSelectedNoFreeNoneSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); lhs->operationComplete( "Add vertices" ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); // No free vertices, they should be deleted even though they weren't // selected. checkUndoRedo( 2, lhs.get(), rhs_list ); } void testDeleteSelectedNoFreeAllSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); lhs->operationComplete( "Add vertices" ); lhs->selectVertex( 0 ); lhs->selectVertex( 1 ); lhs->selectVertex( 2 ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); // No free vertices, they should be deleted even though they weren't // selected. checkUndoRedo( 2, lhs.get(), rhs_list ); } void testDeleteSelectedFreeNoneSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); // No change on the second operation, so there is nothing to undo lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->setVertexFree( 0, true ); lhs->setVertexFree( 1, true ); lhs->setVertexFree( 2, true ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); rhs_full->setVertexFree( 0, true ); rhs_full->setVertexFree( 1, true ); rhs_full->setVertexFree( 2, true ); lhs->operationComplete( "Add vertices" ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); // No free vertices, they should be deleted even though they weren't // selected. checkUndoRedo( 1, lhs.get(), rhs_list ); } void testDeleteSelectedFreeAllSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_full = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_full.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->setVertexFree( 0, true ); lhs->setVertexFree( 1, true ); lhs->setVertexFree( 2, true ); rhs_full->addVertex( 0, 0, 0 ); rhs_full->addVertex( 1, 0, 0 ); rhs_full->addVertex( 1, 1, 0 ); rhs_full->setVertexFree( 0, true ); rhs_full->setVertexFree( 1, true ); rhs_full->setVertexFree( 2, true ); lhs->operationComplete( "Add vertices" ); lhs->selectVertex( 0 ); lhs->selectVertex( 1 ); lhs->selectVertex( 2 ); lhs->deleteSelected(); lhs->operationComplete( "Delete selected" ); // No free vertices, they should be deleted even though they weren't // selected. checkUndoRedo( 2, lhs.get(), rhs_list ); } void testDeleteVertexDeletesTriangle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_triangle = newTestModel(); local_ptr rhs_selected = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_triangle.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_empty.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); rhs_triangle->addVertex( 0, 0, 0 ); rhs_triangle->addVertex( 1, 0, 0 ); rhs_triangle->addVertex( 1, 1, 0 ); rhs_triangle->addTriangle( 0, 1, 2 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->selectVertex( 1 ); lhs->operationComplete( "Add vertices" ); // Deleting one vertex will delete one triangle, but not the other. // Other vertices remain undeleted. lhs->selectVertex( 1 ); lhs->operationComplete( "Select Vertex" ); lhs->deleteSelected(); lhs->operationComplete( "Delete Selected" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testDeleteVertexDeletesSelf() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_triangle = newTestModel(); local_ptr rhs_selected = newTestModel(); local_ptr rhs_deleted = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_triangle.get() ); rhs_list.push_back( rhs_selected.get() ); rhs_list.push_back( rhs_deleted.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 0, 2, 3 ); rhs_triangle->addVertex( 0, 0, 0 ); rhs_triangle->addVertex( 1, 0, 0 ); rhs_triangle->addVertex( 1, 1, 0 ); rhs_triangle->addVertex( 0, 1, 1 ); rhs_triangle->addTriangle( 0, 1, 2 ); rhs_triangle->addTriangle( 0, 2, 3 ); rhs_selected->addVertex( 0, 0, 0 ); rhs_selected->addVertex( 1, 0, 0 ); rhs_selected->addVertex( 1, 1, 0 ); rhs_selected->addVertex( 0, 1, 1 ); rhs_selected->addTriangle( 0, 1, 2 ); rhs_selected->addTriangle( 0, 2, 3 ); rhs_selected->selectVertex( 1 ); rhs_deleted->addVertex( 0, 0, 0 ); rhs_deleted->addVertex( 1, 1, 0 ); rhs_deleted->addVertex( 0, 1, 1 ); rhs_deleted->addTriangle( 0, 1, 2 ); lhs->operationComplete( "Add vertices" ); // Deleting one vertex will delete one triangle, but not the other. // Other vertices remain undeleted. lhs->selectVertex( 1 ); lhs->operationComplete( "Select Vertex" ); lhs->deleteSelected(); lhs->operationComplete( "Delete Selected" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testHideVertexHidesTriangle() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_visible = newTestModel(); local_ptr rhs_hidden = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_visible.get() ); rhs_list.push_back( rhs_hidden.get() ); rhs_list.push_back( rhs_visible.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addTriangle( 0, 1, 2 ); rhs_visible->addVertex( 0, 0, 0 ); rhs_visible->addVertex( 1, 0, 0 ); rhs_visible->addVertex( 1, 1, 0 ); rhs_visible->addTriangle( 0, 1, 2 ); rhs_hidden->addVertex( 0, 0, 0 ); rhs_hidden->addVertex( 1, 0, 0 ); rhs_hidden->addVertex( 1, 1, 0 ); rhs_hidden->addTriangle( 0, 1, 2 ); lhs->operationComplete( "Add vertices" ); // Hiding one vertex will hide the triangle, which hides the // other vertices too. lhs->selectVertex( 0 ); lhs->hideSelected(); rhs_hidden->hideVertex( 0 ); rhs_hidden->hideVertex( 1 ); rhs_hidden->hideVertex( 2 ); rhs_hidden->hideTriangle( 0 ); QVERIFY_FALSE( lhs->isVertexVisible(0) ); QVERIFY_FALSE( lhs->isVertexVisible(1) ); QVERIFY_FALSE( lhs->isVertexVisible(2) ); QVERIFY_FALSE( lhs->isTriangleVisible(0) ); lhs->operationComplete( "Hide Vertices" ); lhs->unhideAll(); QVERIFY_TRUE( lhs->isVertexVisible(0) ); QVERIFY_TRUE( lhs->isVertexVisible(1) ); QVERIFY_TRUE( lhs->isVertexVisible(2) ); QVERIFY_TRUE( lhs->isTriangleVisible(0) ); lhs->operationComplete( "Unhide All" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } void testHideVertexHidesSelf() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_visible = newTestModel(); local_ptr rhs_hidden = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_visible.get() ); rhs_list.push_back( rhs_hidden.get() ); rhs_list.push_back( rhs_visible.get() ); lhs->addVertex( 0, 0, 0 ); lhs->addVertex( 1, 0, 0 ); lhs->addVertex( 1, 1, 0 ); lhs->addVertex( 0, 1, 1 ); lhs->addTriangle( 0, 1, 2 ); lhs->addTriangle( 0, 2, 3 ); rhs_visible->addVertex( 0, 0, 0 ); rhs_visible->addVertex( 1, 0, 0 ); rhs_visible->addVertex( 1, 1, 0 ); rhs_visible->addVertex( 0, 1, 1 ); rhs_visible->addTriangle( 0, 1, 2 ); rhs_visible->addTriangle( 0, 2, 3 ); rhs_hidden->addVertex( 0, 0, 0 ); rhs_hidden->addVertex( 1, 0, 0 ); rhs_hidden->addVertex( 1, 1, 0 ); rhs_hidden->addVertex( 0, 1, 1 ); rhs_hidden->addTriangle( 0, 1, 2 ); rhs_hidden->addTriangle( 0, 2, 3 ); lhs->operationComplete( "Add vertices" ); // Hiding one vertex will hide one triangle, but not the other. // Other vertices remain visible. lhs->selectVertex( 1 ); lhs->hideSelected(); rhs_hidden->hideVertex( 1 ); rhs_hidden->hideTriangle( 0 ); QVERIFY_TRUE( lhs->isVertexVisible(0) ); QVERIFY_FALSE( lhs->isVertexVisible(1) ); QVERIFY_TRUE( lhs->isVertexVisible(2) ); QVERIFY_TRUE( lhs->isVertexVisible(3) ); QVERIFY_FALSE( lhs->isTriangleVisible(0) ); QVERIFY_TRUE( lhs->isTriangleVisible(1) ); lhs->operationComplete( "Hide Vertex" ); lhs->unhideAll(); QVERIFY_TRUE( lhs->isVertexVisible(0) ); QVERIFY_TRUE( lhs->isVertexVisible(1) ); QVERIFY_TRUE( lhs->isVertexVisible(2) ); QVERIFY_TRUE( lhs->isVertexVisible(3) ); QVERIFY_TRUE( lhs->isTriangleVisible(0) ); QVERIFY_TRUE( lhs->isTriangleVisible(1) ); lhs->operationComplete( "Unhide All" ); checkUndoRedo( 3, lhs.get(), rhs_list ); } // FIXME Tests to add (in other files): // // add/remove influences // Frame anim vertex tests // Vertex animated with (weighted) bone joints // Vertex indicies updated in triangles when vertices deleted }; QTEST_MAIN(ModelVertexTest) #include "model_vertex_test.moc" mm3d-master/src/tests/libmm3d/model_weld_test.cc000066400000000000000000000253221324021725400221540ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests vertex welding and unwelding #include #include "test_common.h" #include "model.h" #include "weld.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" class ModelWeldTest : public QObject { Q_OBJECT private: void addWeldTriangles( Model * m, int vertCount ) { if ( vertCount != 3 && vertCount != 4 && vertCount != 5 && vertCount != 6 ) { QTest::qFail( "Vert count was not 3-6", __FILE__, __LINE__ ); exit( -1 ); } m->addVertex( 0, 0, 0 ); m->addVertex( 1, 1, 0 ); m->addVertex( 1, 0, 0 ); if ( vertCount > 3 ) m->addVertex( 2, 0, 0 ); if ( vertCount == 5 ) { m->addVertex( 1, 0, 0 ); } else if ( vertCount == 6 ) { m->addVertex( 1, 1, 0 ); m->addVertex( 1, 0, 0 ); } if ( vertCount == 3 ) { m->addTriangle( 0, 1, 2 ); } else if ( vertCount == 4 ) { m->addTriangle( 0, 1, 2 ); m->addTriangle( 1, 3, 2 ); } else if ( vertCount == 5 ) { m->addTriangle( 0, 1, 2 ); m->addTriangle( 1, 3, 4 ); } else { m->addTriangle( 0, 1, 2 ); m->addTriangle( 4, 3, 5 ); } } void selectAllVertices( Model * m ) { size_t vcount = m->getVertexCount(); for ( size_t v = 0; v < vcount; ++v ) { m->selectVertex( v ); } } private slots: void initTestCase() { log_enable_debug( false ); log_enable_warning( true ); } void testWeldAllSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_fivevert = newTestModel(); local_ptr rhs_fourvert = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_fivevert.get() ); rhs_list.push_back( rhs_fourvert.get() ); addWeldTriangles( lhs.get(), 5 ); addWeldTriangles( rhs_fivevert.get(), 5 ); addWeldTriangles( rhs_fourvert.get(), 4 ); selectAllVertices( lhs.get() ); selectAllVertices( rhs_fivevert.get() ); selectAllVertices( rhs_fourvert.get() ); lhs->selectTriangle( 0 ); rhs_fivevert->selectTriangle( 0 ); rhs_fourvert->selectTriangle( 0 ); lhs->setTextureCoords( 0, 2, 0.3f, 0.4f ); lhs->setTextureCoords( 1, 2, 0.5f, 0.6f ); rhs_fivevert->setTextureCoords( 0, 2, 0.3f, 0.4f ); rhs_fivevert->setTextureCoords( 1, 2, 0.5f, 0.6f ); rhs_fourvert->setTextureCoords( 0, 2, 0.3f, 0.4f ); rhs_fourvert->setTextureCoords( 1, 2, 0.5f, 0.6f ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_FALSE( lhs->propEqual( rhs_fourvert.get() ) ); lhs->operationComplete( "Add triangles" ); int before = 0; int after = 0; weldSelectedVertices( lhs.get(), 0.0001, before, after ); QVERIFY_EQ( 2, before ); QVERIFY_EQ( 1, after ); QVERIFY_FALSE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_TRUE( lhs->propEqual( rhs_fourvert.get() ) ); lhs->operationComplete( "Weld selected" ); // Should be equivalent to both QVERIFY_TRUE( lhs->equivalent( rhs_fivevert.get() ) ); QVERIFY_TRUE( lhs->equivalent( rhs_fourvert.get() ) ); checkUndoRedo( 2, lhs.get(), rhs_list ); } // Nothing selected, nothing to weld void testWeldNoneSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_fivevert = newTestModel(); addWeldTriangles( lhs.get(), 5 ); addWeldTriangles( rhs_fivevert.get(), 5 ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); weldSelectedVertices( lhs.get() ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); } void testWeldTolerance() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_fivevert = newTestModel(); local_ptr rhs_fourvert = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_fivevert.get() ); rhs_list.push_back( rhs_fourvert.get() ); addWeldTriangles( lhs.get(), 5 ); addWeldTriangles( rhs_fivevert.get(), 5 ); addWeldTriangles( rhs_fourvert.get(), 4 ); selectAllVertices( lhs.get() ); selectAllVertices( rhs_fivevert.get() ); selectAllVertices( rhs_fourvert.get() ); lhs->moveVertex( 4, 1.1, 0, 0 ); rhs_fivevert->moveVertex( 4, 1.1, 0, 0 ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_FALSE( lhs->propEqual( rhs_fourvert.get() ) ); lhs->operationComplete( "Add triangles" ); // Not close enough to weld weldSelectedVertices( lhs.get(), 0.09 ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_FALSE( lhs->propEqual( rhs_fourvert.get() ) ); // Close enough to weld weldSelectedVertices( lhs.get(), 0.11 ); QVERIFY_FALSE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_TRUE( lhs->propEqual( rhs_fourvert.get() ) ); lhs->operationComplete( "Weld selected" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } // Tests that triangles that get two vertices merged into one // are deleted. void testWeldDeleteFlattened() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_fivevert = newTestModel(); local_ptr rhs_threevert = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_fivevert.get() ); rhs_list.push_back( rhs_threevert.get() ); addWeldTriangles( lhs.get(), 5 ); addWeldTriangles( rhs_fivevert.get(), 5 ); addWeldTriangles( rhs_threevert.get(), 3 ); selectAllVertices( lhs.get() ); selectAllVertices( rhs_fivevert.get() ); selectAllVertices( rhs_threevert.get() ); lhs->moveVertex( 3, 1, 0, 0 ); rhs_fivevert->moveVertex( 3, 1, 0, 0 ); QVERIFY_TRUE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_FALSE( lhs->propEqual( rhs_threevert.get() ) ); lhs->operationComplete( "Add triangles" ); int before = 0; int after = 0; weldSelectedVertices( lhs.get(), 0.0001, before, after ); QVERIFY_EQ( 3, before ); QVERIFY_EQ( 1, after ); QVERIFY_FALSE( lhs->propEqual( rhs_fivevert.get() ) ); QVERIFY_TRUE( lhs->propEqual( rhs_threevert.get() ) ); lhs->operationComplete( "Weld selected" ); checkUndoRedo( 2, lhs.get(), rhs_list ); } void testUnweldAllSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_empty = newTestModel(); local_ptr rhs_fourvert = newTestModel(); local_ptr rhs_sixvert = newTestModel(); ModelList rhs_list; rhs_list.push_back( rhs_empty.get() ); rhs_list.push_back( rhs_fourvert.get() ); rhs_list.push_back( rhs_sixvert.get() ); addWeldTriangles( lhs.get(), 4 ); addWeldTriangles( rhs_fourvert.get(), 4 ); addWeldTriangles( rhs_sixvert.get(), 6 ); selectAllVertices( lhs.get() ); selectAllVertices( rhs_sixvert.get() ); selectAllVertices( rhs_fourvert.get() ); lhs->selectTriangle( 0 ); rhs_sixvert->selectTriangle( 0 ); rhs_fourvert->selectTriangle( 0 ); lhs->setTextureCoords( 0, 2, 0.3f, 0.4f ); lhs->setTextureCoords( 1, 2, 0.5f, 0.6f ); rhs_sixvert->setTextureCoords( 0, 2, 0.3f, 0.4f ); rhs_sixvert->setTextureCoords( 1, 2, 0.5f, 0.6f ); rhs_fourvert->setTextureCoords( 0, 2, 0.3f, 0.4f ); rhs_fourvert->setTextureCoords( 1, 2, 0.5f, 0.6f ); lhs->addBoneJoint( "Parent", 1, 1, 1, 0, 0, 0 ); lhs->addBoneJoint( "Child", 1, 1, 1, 0, 0, 0, 0 ); rhs_sixvert->addBoneJoint( "Parent", 1, 1, 1, 0, 0, 0 ); rhs_sixvert->addBoneJoint( "Child", 1, 1, 1, 0, 0, 0, 0 ); rhs_fourvert->addBoneJoint( "Parent", 1, 1, 1, 0, 0, 0 ); rhs_fourvert->addBoneJoint( "Child", 1, 1, 1, 0, 0, 0, 0 ); lhs->addVertexInfluence( 2, 0, Model::IT_Custom, 0.7 ); lhs->addVertexInfluence( 2, 0, Model::IT_Custom, 0.3 ); rhs_sixvert->addVertexInfluence( 2, 0, Model::IT_Custom, 0.7 ); rhs_sixvert->addVertexInfluence( 2, 0, Model::IT_Custom, 0.3 ); rhs_sixvert->addVertexInfluence( 5, 0, Model::IT_Custom, 0.7 ); rhs_sixvert->addVertexInfluence( 5, 0, Model::IT_Custom, 0.3 ); rhs_fourvert->addVertexInfluence( 2, 0, Model::IT_Custom, 0.7 ); rhs_fourvert->addVertexInfluence( 2, 0, Model::IT_Custom, 0.3 ); QVERIFY_TRUE( lhs->propEqual( rhs_fourvert.get() ) ); QVERIFY_FALSE( lhs->propEqual( rhs_sixvert.get() ) ); lhs->operationComplete( "Add triangles" ); int before = 0; int after = 0; unweldSelectedVertices( lhs.get(), after, before ); QVERIFY_EQ( 4, before ); QVERIFY_EQ( 6, after ); QVERIFY_FALSE( lhs->propEqual( rhs_fourvert.get() ) ); QVERIFY_TRUE( lhs->propEqual( rhs_sixvert.get() ) ); lhs->operationComplete( "Unweld selected" ); // Should be equivalent to both QVERIFY_TRUE( lhs->equivalent( rhs_sixvert.get() ) ); QVERIFY_TRUE( lhs->equivalent( rhs_fourvert.get() ) ); checkUndoRedo( 2, lhs.get(), rhs_list ); } // Nothing selected, nothing to unweld void testUnweldNoneSelected() { local_ptr lhs = newTestModel(); local_ptr rhs_fourvert = newTestModel(); addWeldTriangles( lhs.get(), 4 ); addWeldTriangles( rhs_fourvert.get(), 4 ); QVERIFY_TRUE( lhs->propEqual( rhs_fourvert.get() ) ); unweldSelectedVertices( lhs.get() ); QVERIFY_TRUE( lhs->propEqual( rhs_fourvert.get() ) ); } }; QTEST_MAIN(ModelWeldTest) #include "model_weld_test.moc" mm3d-master/src/tests/libmm3d/msg_test.cc000066400000000000000000000114521324021725400206260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests msg.cc #include #include #include #include #include #include "test_common.h" #include "msg.h" static int info_msg_count = 0; static int warning_msg_count = 0; static int error_msg_count = 0; static std::string display_msg = ""; void custom_info_msg( const char * msg ) { ++info_msg_count; display_msg = msg; } void custom_warning_msg( const char * msg ) { ++warning_msg_count; display_msg = msg; } void custom_error_msg( const char * msg ) { ++error_msg_count; display_msg = msg; } char prompt_yes( const char * str, const char * opts ) { display_msg = str; return 'Y'; } char prompt_no( const char * str, const char * opts ) { display_msg = str; return 'N'; } char prompt_cancel( const char * str, const char * opts ) { display_msg = str; return 'C'; } class MessageTest : public QObject { Q_OBJECT private slots: void init() { msg_register( NULL, NULL, NULL ); display_msg = ""; info_msg_count = 0; warning_msg_count = 0; error_msg_count = 0; } void testInfoMessage() { const std::string msg = "Info message"; msg_info( msg.c_str() ); QVERIFY_EQ( std::string(""), display_msg ); QVERIFY_EQ( 0, info_msg_count ); msg_register( custom_info_msg, custom_warning_msg, custom_error_msg ); msg_info( msg.c_str() ); QVERIFY_EQ( msg, display_msg ); QVERIFY_EQ( 1, info_msg_count ); QVERIFY_EQ( 0, warning_msg_count ); QVERIFY_EQ( 0, error_msg_count ); } void testWarningMessage() { const std::string msg = "Warning message"; msg_warning( msg.c_str() ); QVERIFY_EQ( std::string(""), display_msg ); QVERIFY_EQ( 0, info_msg_count ); msg_register( custom_info_msg, custom_warning_msg, custom_error_msg ); msg_warning( msg.c_str() ); QVERIFY_EQ( msg, display_msg ); QVERIFY_EQ( 0, info_msg_count ); QVERIFY_EQ( 1, warning_msg_count ); QVERIFY_EQ( 0, error_msg_count ); } void testErrorMessage() { const std::string msg = "Error message"; msg_error( msg.c_str() ); QVERIFY_EQ( std::string(""), display_msg ); QVERIFY_EQ( 0, info_msg_count ); msg_register( custom_info_msg, custom_warning_msg, custom_error_msg ); msg_error( msg.c_str() ); QVERIFY_EQ( msg, display_msg ); QVERIFY_EQ( 0, info_msg_count ); QVERIFY_EQ( 0, warning_msg_count ); QVERIFY_EQ( 1, error_msg_count ); } void testDefaultPrompt() { QVERIFY_EQ( 'Y', msg_info_prompt( "Yes message", "Ync" ) ); QVERIFY_EQ( 'Y', msg_info_prompt( "Yes message", "nYc" ) ); QVERIFY_EQ( 'Y', msg_info_prompt( "Yes message", "cnY" ) ); QVERIFY_EQ( 'N', msg_warning_prompt( "No message", "yNc" ) ); QVERIFY_EQ( 'N', msg_warning_prompt( "No message", "Nyc" ) ); QVERIFY_EQ( 'N', msg_warning_prompt( "No message", "ycN" ) ); QVERIFY_EQ( 'C', msg_error_prompt( "Cancel message", "ynC" ) ); QVERIFY_EQ( 'C', msg_error_prompt( "Cancel message", "yCn" ) ); QVERIFY_EQ( 'C', msg_error_prompt( "Cancel message", "Cyn" ) ); QVERIFY_EQ( 'Y', msg_error_prompt( "No default", "ync" ) ); QVERIFY_EQ( 'C', msg_error_prompt( "No default", "cny" ) ); QVERIFY_EQ( '\0', msg_error_prompt( "Empty message", "" ) ); QVERIFY_EQ( '\0', msg_error_prompt( "NULL message", NULL ) ); } void testCustomPrompt() { msg_register_prompt( prompt_yes, prompt_no, prompt_cancel ); std::string msg; msg = "Info prompt message"; QVERIFY_EQ( 'Y', msg_info_prompt( msg.c_str() ) ); QVERIFY_EQ( msg, display_msg ); msg = "Warning prompt message"; QVERIFY_EQ( 'N', msg_warning_prompt( msg.c_str() ) ); QVERIFY_EQ( msg, display_msg ); msg = "Error prompt message"; QVERIFY_EQ( 'C', msg_error_prompt( msg.c_str() ) ); QVERIFY_EQ( msg, display_msg ); } }; QTEST_MAIN(MessageTest) #include "msg_test.moc" mm3d-master/src/tests/libmm3d/new_mm3d_test.cc000066400000000000000000000056771324021725400215650ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the MM3D model file filter against a reference version. // FIXME add more models (particularly textured ones) #include #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "log.h" #include "mm3dfilter.h" #include "mm3dfilter_ref.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" Model * loadModelOrDie( const char * filename, bool useReference ) { Model * model = new Model; local_ptr f; if ( useReference ) f = new MisfitFilterRef; else f = new MisfitFilter; Model::ModelErrorE err = f->readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "fatal: %s: %s\n", filename, Model::errorToString( err ) ); delete model; exit( -1 ); } model->forceAddOrDelete( true ); return model; } //void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) //{ // // FIXME hack //} class NewMm3dTest : public QObject { Q_OBJECT private: void testModelFile( const char * file ) { // The lhs pointer is from the original filter local_ptr lhs = loadModelOrDie( file, true ); local_ptr rhs = loadModelOrDie( file, false ); QVERIFY_TRUE( lhs->propEqual( rhs.get() ) ); // FIXME should really use a temp file based on something // unique (hostname-pid?) so that multiple tests could run in parallel. const char tmpFile[] = "tmp_new_mm3d_test.mm3d"; MisfitFilter f; QVERIFY_EQ( Model::ERROR_NONE, f.writeFile( rhs.get(), tmpFile ) ); local_ptr written = loadModelOrDie( tmpFile, false ); QVERIFY_EQ( 0, unlink( tmpFile ) ); } private slots: void initTestCase() { log_enable_debug( false ); } void testModelEqualTest() { testModelFile( "data/model_equal_test.mm3d" ); } void testModelHiddenTest() { testModelFile( "data/model_hidden_test.mm3d" ); } }; QTEST_MAIN(NewMm3dTest) #include "new_mm3d_test.moc" mm3d-master/src/tests/libmm3d/texcompare_test.cc000066400000000000000000000076071324021725400222160ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the equality of texture data #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "tgatex.h" #include "log.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" Texture * loadTextureOrDie( TextureFilter * f, const char * filename ) { Texture * tex = new Texture; Texture::ErrorE err = f->readFile( tex, filename ); if ( err != Texture::ERROR_NONE ) { fprintf( stderr, "fatal: %s: %s\n", filename, Texture::errorToString( err ) ); delete tex; exit( -1 ); } return tex; } Texture * loadTgaOrDie( const char * filename ) { TgaTextureFilter f; return loadTextureOrDie( &f, filename ); } Texture * loadOldTgaOrDie( const char * filename ) { OldTgaTextureFilter f; return loadTextureOrDie( &f, filename ); } class TextureCompareTest : public QObject { Q_OBJECT private slots: void initTestCase() { log_enable_debug( false ); } void testTgaOldNewRgbUncomp() { local_ptr lhs = loadOldTgaOrDie( "data/test_rgb_uncomp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgb_uncomp.tga" ); Texture::CompareResultT res; QVERIFY_TRUE( lhs->compare( rhs.get(), &res, 0 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_TRUE( res.pixelCount > 0 ); QVERIFY_EQ( res.pixelCount, res.matchCount ); QVERIFY_EQ( res.pixelCount, res.fuzzyCount ); } void testTgaOldNewRgbaUncomp() { local_ptr lhs = loadOldTgaOrDie( "data/test_rgba_uncomp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgba_uncomp.tga" ); Texture::CompareResultT res; QVERIFY_TRUE( lhs->compare( rhs.get(), &res, 0 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_TRUE( res.pixelCount > 0 ); QVERIFY_EQ( res.pixelCount, res.matchCount ); QVERIFY_EQ( res.pixelCount, res.fuzzyCount ); } void testTgaOldNewRgbComp() { local_ptr lhs = loadOldTgaOrDie( "data/test_rgb_comp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgb_comp.tga" ); Texture::CompareResultT res; QVERIFY_TRUE( lhs->compare( rhs.get(), &res, 0 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_TRUE( res.pixelCount > 0 ); QVERIFY_EQ( res.pixelCount, res.matchCount ); QVERIFY_EQ( res.pixelCount, res.fuzzyCount ); } void testTgaOldNewRgbaComp() { local_ptr lhs = loadOldTgaOrDie( "data/test_rgba_comp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgba_comp.tga" ); Texture::CompareResultT res; QVERIFY_TRUE( lhs->compare( rhs.get(), &res, 0 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_TRUE( res.pixelCount > 0 ); QVERIFY_EQ( res.pixelCount, res.matchCount ); QVERIFY_EQ( res.pixelCount, res.fuzzyCount ); } }; QTEST_MAIN(TextureCompareTest) #include "texcompare_test.moc" mm3d-master/src/tests/libmm3d/texscale_test.cc000066400000000000000000000071041324021725400216470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests the equality of texture data #include #include "test_common.h" #include "model.h" #include "texture.h" #include "modelstatus.h" #include "tgatex.h" #include "log.h" #include "texscale.h" #include "local_array.h" #include "local_ptr.h" #include "release_ptr.h" Texture * loadTextureOrDie( TextureFilter * f, const char * filename ) { Texture * tex = new Texture; Texture::ErrorE err = f->readFile( tex, filename ); if ( err != Texture::ERROR_NONE ) { fprintf( stderr, "fatal: %s: %s\n", filename, Texture::errorToString( err ) ); delete tex; exit( -1 ); } return tex; } Texture * loadTgaOrDie( const char * filename ) { TgaTextureFilter f; return loadTextureOrDie( &f, filename ); } class TextureScaleTest : public QObject { Q_OBJECT void scaleTexture( Texture * tex ) { uint8_t * oldData = tex->m_data; tex->m_data = texture_scale_auto( tex->m_data, tex->m_format, tex->m_width, tex->m_height ); delete[] oldData; } private slots: void initTestCase() { log_enable_debug( false ); } void testScaleDown() { local_ptr lhs = loadTgaOrDie( "data/test_rgb_uncomp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgb_300.tga" ); QVERIFY_FALSE( texture_scale_need_scale( lhs->m_width, lhs->m_height ) ); QVERIFY_TRUE( texture_scale_need_scale( rhs->m_width, rhs->m_height ) ); scaleTexture( rhs.get() ); Texture::CompareResultT res; QVERIFY_FALSE( lhs->compare( rhs.get(), &res, 0 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_EQ( 65536, (int) res.pixelCount ); QVERIFY_LT( (int) (65536.0 * 0.95), (int) res.matchCount ); QVERIFY_LT( (int) (65536.0 * 0.95), (int) res.fuzzyCount ); } void testScaleUp() { local_ptr lhs = loadTgaOrDie( "data/test_rgba_uncomp.tga" ); local_ptr rhs = loadTgaOrDie( "data/test_rgba_200.tga" ); QVERIFY_FALSE( texture_scale_need_scale( lhs->m_width, lhs->m_height ) ); QVERIFY_TRUE( texture_scale_need_scale( rhs->m_width, rhs->m_height ) ); scaleTexture( rhs.get() ); Texture::CompareResultT res; QVERIFY_FALSE( lhs->compare( rhs.get(), &res, 32 ) ); QVERIFY_TRUE( res.comparable ); QVERIFY_EQ( 65536, (int) res.pixelCount ); QVERIFY_LT( (int) (65536.0 * 0.91), (int) res.matchCount ); QVERIFY_LT( (int) (65536.0 * 0.95), (int) res.fuzzyCount ); } void testScaleZero() { QVERIFY_FALSE( texture_scale_need_scale( 0, 0 ) ); } }; QTEST_MAIN(TextureScaleTest) #include "texscale_test.moc" mm3d-master/src/tests/libmm3d/translation_test.cc000066400000000000000000000044761324021725400224060ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests translate.cc and mlocale.cc #include #include #include #include #include "test_common.h" #include "translate.h" #include "mlocale.h" std::string test_translate_function( const char * sourceStr ) { if ( strcmp( sourceStr, "foo" ) == 0 ) return "goo"; else if ( strcmp( sourceStr, "bar" ) == 0 ) return "ber"; return sourceStr; } class TranslationTest : public QObject { Q_OBJECT private slots: void testNoTranslate() { transll_install_handler( NULL ); QVERIFY_EQ( std::string("foo"), transll(QT_TRANSLATE_NOOP("Test", "foo")) ); QVERIFY_EQ( std::string("bar"), transll(QT_TRANSLATE_NOOP("Test", "bar")) ); QVERIFY_EQ( std::string("baz"), transll(QT_TRANSLATE_NOOP("Test", "baz")) ); } void testTranslate() { transll_install_handler( test_translate_function ); QVERIFY_EQ( std::string("goo"), transll(QT_TRANSLATE_NOOP("Test", "foo")) ); QVERIFY_EQ( std::string("ber"), transll(QT_TRANSLATE_NOOP("Test", "bar")) ); QVERIFY_EQ( std::string("baz"), transll(QT_TRANSLATE_NOOP("Test", "baz")) ); transll_install_handler( NULL ); } void testLocale() { QVERIFY_EQ( std::string(""), mlocale_get() ); mlocale_set("en-GB"); QVERIFY_EQ( std::string("en-GB"), mlocale_get() ); mlocale_set(""); QVERIFY_EQ( std::string(""), mlocale_get() ); } }; QTEST_MAIN(TranslationTest) #include "translation_test.moc" mm3d-master/src/tests/libmm3d/undomgr_test.cc000066400000000000000000000562471324021725400215260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests local_ptr.h, local_array.h, release_ptr.h, // and file_closer.h #include #include #include #include #include "test_common.h" #include "log.h" #include "undomgr.h" #include "undo.h" class TestUndo : public Undo { public: TestUndo() : m_size( 0 ), m_useBaseSize( true ), m_undoReleaseCalled( false ), m_redoReleaseCalled( false ), m_releaseCalled( false ), m_canCombine( false ) { } virtual ~TestUndo() { } bool combine( Undo * u ) { TestUndo * undo = static_cast(u); return m_canCombine && undo->m_canCombine; } void undoRelease() { m_undoReleaseCalled = true; } void redoRelease() { m_redoReleaseCalled = true; } void release() { m_releaseCalled = true; } unsigned size() { return m_size + (m_useBaseSize ? Undo::size() : 0); } unsigned int m_size; bool m_useBaseSize; bool m_undoReleaseCalled; bool m_redoReleaseCalled; bool m_releaseCalled; bool m_canCombine; }; class UndoMgrTest : public QObject { Q_OBJECT private slots: void initTestCase() { log_enable_debug( false ); } void testBasicUndoTest() { TestUndo u1; TestUndo u2; TestUndo u3; UndoManager mgr; QVERIFY_FALSE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op1" ), std::string( mgr.getUndoOpName() ) ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getUndoOpName() ) ); mgr.addUndo( &u3 ); mgr.operationComplete( "Op3" ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op3" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_TRUE( NULL != mgr.undo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_EQ( std::string( "Op3" ), std::string( mgr.getRedoOpName() ) ); QVERIFY_TRUE( NULL != mgr.undo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op1" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getRedoOpName() ) ); QVERIFY_TRUE( NULL != mgr.undo() ); QVERIFY_FALSE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op1" ), std::string( mgr.getRedoOpName() ) ); QVERIFY_TRUE( NULL == mgr.undo() ); QVERIFY_TRUE( NULL != mgr.redo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op1" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getRedoOpName() ) ); QVERIFY_TRUE( NULL != mgr.redo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_EQ( std::string( "Op3" ), std::string( mgr.getRedoOpName() ) ); QVERIFY_TRUE( NULL != mgr.redo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); QVERIFY_EQ( std::string( "Op3" ), std::string( mgr.getUndoOpName() ) ); QVERIFY_TRUE( NULL == mgr.redo() ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); } void testUndoRelease() { TestUndo u1; TestUndo u2; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); mgr.undo(); mgr.redo(); mgr.undo(); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_redoReleaseCalled ); } void testUndoCombine() { TestUndo u1; TestUndo u2; TestUndo u3; TestUndo u4; u3.m_canCombine = true; u4.m_canCombine = true; UndoManager mgr; mgr.addUndo( &u1 ); mgr.addUndo( &u2 ); mgr.addUndo( &u3 ); mgr.addUndo( &u4 ); mgr.operationComplete( "Op1" ); UndoList * ul = mgr.undo(); QVERIFY_EQ( 3, (int) ul->size() ); QVERIFY_TRUE( NULL == mgr.undo() ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); } void testUndoNoCombine() { TestUndo u1; TestUndo u2; // Combine fails because they are separate operations u1.m_canCombine = true; u2.m_canCombine = true; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); UndoList * ul; ul = mgr.undo(); QVERIFY_EQ( 1, (int) ul->size() ); ul = mgr.undo(); QVERIFY_EQ( 1, (int) ul->size() ); QVERIFY_TRUE( NULL == mgr.undo() ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); } void testOperationCompleteWithoutOp() { TestUndo u1; TestUndo u2; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.operationComplete( "No Op" ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); UndoList * ul; QVERIFY_EQ( std::string( "Op2" ), std::string( mgr.getUndoOpName() ) ); ul = mgr.undo(); QVERIFY_EQ( 1, (int) ul->size() ); QVERIFY_EQ( std::string( "Op1" ), std::string( mgr.getUndoOpName() ) ); ul = mgr.undo(); QVERIFY_EQ( 1, (int) ul->size() ); QVERIFY_FALSE( mgr.canUndo() ); QVERIFY_TRUE( NULL == mgr.undo() ); } void testUndoOperationComplete() { TestUndo u1; TestUndo u2; TestUndo u3; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); QVERIFY_TRUE( NULL != mgr.undo() ); mgr.addUndo( &u3 ); mgr.operationComplete( "Op3" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_TRUE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_TRUE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_TRUE( u3.m_undoReleaseCalled ); } void testSizeLimit() { TestUndo u1; TestUndo u2; TestUndo u3; TestUndo u4; TestUndo u5; u1.m_size = 10; u1.m_useBaseSize = false; u2.m_size = 10; u2.m_useBaseSize = false; u3.m_size = 10; u3.m_useBaseSize = false; u4.m_size = 10; u4.m_useBaseSize = false; u5.m_size = 10; u5.m_useBaseSize = false; UndoManager mgr; mgr.setSizeLimit( 35 ); mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u3 ); mgr.operationComplete( "Op3" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u4 ); mgr.operationComplete( "Op4" ); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u5 ); mgr.operationComplete( "Op5" ); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); QVERIFY_TRUE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_undoReleaseCalled ); QVERIFY_TRUE( u3.m_undoReleaseCalled ); QVERIFY_TRUE( u4.m_undoReleaseCalled ); QVERIFY_TRUE( u5.m_undoReleaseCalled ); } void testCountLimit() { TestUndo u1; TestUndo u2; TestUndo u3; TestUndo u4; TestUndo u5; UndoManager mgr; mgr.setCountLimit( 3 ); mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u3 ); mgr.operationComplete( "Op3" ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_FALSE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u4 ); mgr.operationComplete( "Op4" ); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.addUndo( &u5 ); mgr.operationComplete( "Op5" ); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); QVERIFY_FALSE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u3.m_undoReleaseCalled ); QVERIFY_FALSE( u4.m_undoReleaseCalled ); QVERIFY_FALSE( u5.m_undoReleaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); QVERIFY_TRUE( u5.m_releaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); QVERIFY_FALSE( u3.m_redoReleaseCalled ); QVERIFY_FALSE( u4.m_redoReleaseCalled ); QVERIFY_FALSE( u5.m_redoReleaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_undoReleaseCalled ); QVERIFY_TRUE( u3.m_undoReleaseCalled ); QVERIFY_TRUE( u4.m_undoReleaseCalled ); QVERIFY_TRUE( u5.m_undoReleaseCalled ); } void testUndoCurrent() { { TestUndo u1; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); QVERIFY_TRUE( NULL == mgr.undoCurrent() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); } { TestUndo u1; TestUndo u2; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); QVERIFY_TRUE( NULL != mgr.undoCurrent() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_TRUE( mgr.canRedo() ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_FALSE( u2.m_undoReleaseCalled ); QVERIFY_TRUE( u2.m_redoReleaseCalled ); } { TestUndo u1; TestUndo u2; UndoManager mgr; mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); QVERIFY_TRUE( NULL != mgr.undoCurrent() ); QVERIFY_TRUE( NULL != mgr.redo() ); QVERIFY_TRUE( mgr.canUndo() ); QVERIFY_FALSE( mgr.canRedo() ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u1.m_undoReleaseCalled ); QVERIFY_FALSE( u1.m_redoReleaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u2.m_undoReleaseCalled ); QVERIFY_FALSE( u2.m_redoReleaseCalled ); } } void testListCombine() { // Without list combine { TestUndo u1; TestUndo u2; TestUndo u3; TestUndo u4; u2.m_canCombine = true; u4.m_canCombine = true; UndoManager mgr; mgr.addUndo( &u1 ); mgr.addUndo( &u2 ); mgr.addUndo( &u3 ); mgr.addUndo( &u4 ); mgr.operationComplete( "Op1" ); UndoList * ul = mgr.undo(); QVERIFY_EQ( 4, (int) ul->size() ); QVERIFY_TRUE( NULL == mgr.undo() ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_FALSE( u4.m_releaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); } // With list combine { TestUndo u1; TestUndo u2; TestUndo u3; TestUndo u4; u2.m_canCombine = true; u4.m_canCombine = true; UndoManager mgr; mgr.addUndo( &u1, true ); mgr.addUndo( &u2, true ); mgr.addUndo( &u3, true ); mgr.addUndo( &u4, true ); mgr.operationComplete( "Op1" ); UndoList * ul = mgr.undo(); QVERIFY_EQ( 3, (int) ul->size() ); QVERIFY_TRUE( NULL == mgr.undo() ); QVERIFY_FALSE( u1.m_releaseCalled ); QVERIFY_FALSE( u2.m_releaseCalled ); QVERIFY_FALSE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); mgr.clear(); QVERIFY_TRUE( u1.m_releaseCalled ); QVERIFY_TRUE( u2.m_releaseCalled ); QVERIFY_TRUE( u3.m_releaseCalled ); QVERIFY_TRUE( u4.m_releaseCalled ); } } void testSetSaved() { TestUndo u1; TestUndo u2; TestUndo u3; UndoManager mgr; mgr.setSaved(); mgr.addUndo( &u1 ); mgr.operationComplete( "Op1" ); mgr.addUndo( &u2 ); mgr.operationComplete( "Op2" ); mgr.addUndo( &u3 ); mgr.operationComplete( "Op3" ); // Save undo = 0 QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_TRUE( mgr.isSaved() ); // Save undo = 1 mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.setSaved(); QVERIFY_TRUE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); // Save undo = 2 mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.setSaved(); QVERIFY_TRUE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_TRUE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); // Save undo = 3 mgr.setSaved(); QVERIFY_TRUE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.undo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_FALSE( mgr.isSaved() ); mgr.redo(); QVERIFY_TRUE( mgr.isSaved() ); } // Cover last of the undomgr.cc file void testOpNameTest() { TestUndo u1; UndoManager mgr; QVERIFY_EQ(std::string(""), std::string(mgr.getUndoOpName())); QVERIFY_EQ(std::string(""), std::string(mgr.getRedoOpName())); // Don't call operation complete here mgr.addUndo( &u1 ); QVERIFY_EQ(std::string(""), std::string(mgr.getUndoOpName())); } }; QTEST_MAIN(UndoMgrTest) #include "undomgr_test.moc" mm3d-master/src/tests/libmm3d/util_test.cc000066400000000000000000000035231324021725400210150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2007-2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ // This file tests libmm3d/util.h #include #include "test_common.h" #include "util.h" class UtilTest : public QObject { Q_OBJECT private slots: void testClamp() { QVERIFY_EQ( 5, util_clamp(5, 2, 7 ) ); QVERIFY_EQ( 2, util_clamp(2, 2, 7 ) ); QVERIFY_EQ( 7, util_clamp(7, 2, 7 ) ); QVERIFY_EQ( 2, util_clamp(1, 2, 7 ) ); QVERIFY_EQ( 7, util_clamp(8, 2, 7 ) ); } void testWrapUp() { QVERIFY_EQ( 5, util_wrap_up(5, 2, 7 ) ); QVERIFY_EQ( 2, util_wrap_up(2, 2, 7 ) ); QVERIFY_EQ( 7, util_wrap_up(7, 2, 7 ) ); QVERIFY_EQ( 2, util_wrap_up(1, 2, 7 ) ); QVERIFY_EQ( 2, util_wrap_up(8, 2, 7 ) ); } void testWrapDown() { QVERIFY_EQ( 5, util_wrap_down(5, 2, 7 ) ); QVERIFY_EQ( 2, util_wrap_down(2, 2, 7 ) ); QVERIFY_EQ( 7, util_wrap_down(7, 2, 7 ) ); QVERIFY_EQ( 7, util_wrap_down(1, 2, 7 ) ); QVERIFY_EQ( 7, util_wrap_down(8, 2, 7 ) ); } }; QTEST_MAIN(UtilTest) #include "util_test.moc" mm3d-master/src/tests/profile/000077500000000000000000000000001324021725400166005ustar00rootroot00000000000000mm3d-master/src/tests/profile/Makefile000066400000000000000000000005221324021725400202370ustar00rootroot00000000000000include ../Makefile.common LIBS = ../../libmm3d/libmm3d.a # Add profile tests here PROFILES = \ load_md3.prof \ calc_fnormals.prof \ calc_normals.prof \ group_triangles.prof \ all: $(PROFILES) clean: rm -rf *.prof *.moc core core.* *.gcno *.gcda .cc.prof: $(CXX) $(CXXFLAGS) -pg -o $*.prof $< $(LIBS) $(TESTLIBS) mm3d-master/src/tests/profile/calc_fnormals.cc000066400000000000000000000024161324021725400217150ustar00rootroot00000000000000#include #include #include "model.h" #include "modelstatus.h" #include "mm3dfilter.h" #include "md3filter.h" #include "msg.h" char prompt_func( const char * str, const char * opts ) { return 'Y'; } void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) { // FIXME hack } Model * loadModel( const char * filename ) { Md3Filter f; Model * model = new Model; Model::ModelErrorE err = f.readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "%s: %s\n", filename, Model::errorToString( err ) ); delete model; return NULL; } return model; } int main( int argc, char * argv[] ) { if ( argc < 2 ) { fprintf( stderr, "No model files specified\n" ); return -1; } msg_register_prompt( prompt_func, prompt_func, prompt_func ); for ( int a = 1; a < argc; a++ ) { printf( "testing normal calculation for %s\n", argv[a] ); Model * model = loadModel( argv[a] ); if ( model ) { unsigned int acount = model->getAnimCount( Model::ANIMMODE_FRAME ); for ( unsigned int anim = 0; anim < acount; anim++ ) model->calculateFrameNormals( anim ); delete model; } } return 0; } mm3d-master/src/tests/profile/calc_normals.cc000066400000000000000000000017531324021725400215520ustar00rootroot00000000000000#include #include #include "model.h" #include "modelstatus.h" #include "mm3dfilter.h" void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) { // FIXME hack } Model * loadModel( const char * filename ) { MisfitFilter f; Model * model = new Model; Model::ModelErrorE err = f.readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "%s: %s\n", filename, Model::errorToString( err ) ); delete model; return NULL; } return model; } int main( int argc, char * argv[] ) { if ( argc < 2 ) { fprintf( stderr, "No model files specified\n" ); return -1; } for ( int a = 1; a < argc; a++ ) { printf( "testing normal calculation for %s\n", argv[a] ); Model * model = loadModel( argv[a] ); if ( model ) { for ( int t = 0; t < 25; ++t ) model->calculateNormals(); delete model; } } return 0; } mm3d-master/src/tests/profile/group_triangles.cc000066400000000000000000000046531324021725400223230ustar00rootroot00000000000000#include #include #include "model.h" #include "modelstatus.h" #include "mm3dfilter.h" void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) { // FIXME hack } Model * loadModel( const char * filename ) { MisfitFilter f; Model * model = new Model; Model::ModelErrorE err = f.readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "%s: %s\n", filename, Model::errorToString( err ) ); delete model; return NULL; } return model; } int main( int argc, char * argv[] ) { if ( argc < 2 ) { fprintf( stderr, "No model files specified\n" ); return -1; } for ( int a = 1; a < argc; a++ ) { printf( "testing group triangles for %s\n", argv[a] ); Model * model = loadModel( argv[a] ); if ( model ) { int tcount = model->getTriangleCount(); int grp = model->addGroup( "New group" ); // Up, Up for ( int t = 0; t < tcount; ++t ) { model->addTriangleToGroup( grp, t ); } for ( int t = 0; t < tcount; ++t ) { model->getTriangleGroup( t ); } for ( int t = 0; t < tcount; ++t ) { model->removeTriangleFromGroup( grp, t ); } // Up, Down for ( int t = 0; t < tcount; ++t ) { model->addTriangleToGroup( grp, t ); } for ( int t = 0; t < tcount; ++t ) { model->getTriangleGroup( t ); } for ( int t = tcount - 1; t > 0; --t ) { model->removeTriangleFromGroup( grp, t ); } // Down, Down for ( int t = tcount - 1; t > 0; --t ) { model->addTriangleToGroup( grp, t ); } for ( int t = 0; t < tcount; ++t ) { model->getTriangleGroup( t ); } for ( int t = tcount - 1; t > 0; --t ) { model->removeTriangleFromGroup( grp, t ); } // Down, Up for ( int t = tcount - 1; t > 0; --t ) { model->addTriangleToGroup( grp, t ); } for ( int t = 0; t < tcount; ++t ) { model->getTriangleGroup( t ); } for ( int t = 0; t > tcount; ++t ) { model->removeTriangleFromGroup( grp, t ); } } } return 0; } mm3d-master/src/tests/profile/load_md3.cc000066400000000000000000000020671324021725400205760ustar00rootroot00000000000000#include #include #include "model.h" #include "modelstatus.h" #include "mm3dfilter.h" #include "md3filter.h" #include "msg.h" char prompt_func( const char * str, const char * opts ) { return 'Y'; } void model_status( Model * model, StatusTypeE type, unsigned ms, const char * fmt, ... ) { // FIXME hack } Model * loadModel( const char * filename ) { Md3Filter f; Model * model = new Model; Model::ModelErrorE err = f.readFile( model, filename ); if ( err != Model::ERROR_NONE ) { fprintf( stderr, "%s: %s\n", filename, Model::errorToString( err ) ); delete model; return NULL; } return model; } int main( int argc, char * argv[] ) { if ( argc < 2 ) { fprintf( stderr, "No model files specified\n" ); return -1; } msg_register_prompt( prompt_func, prompt_func, prompt_func ); for ( int a = 1; a < argc; a++ ) { printf( "testing load time for %s\n", argv[a] ); Model * model = loadModel( argv[a] ); if ( model ) delete model; } return 0; } mm3d-master/src/tools/000077500000000000000000000000001324021725400151365ustar00rootroot00000000000000mm3d-master/src/tools/Makefile.am000066400000000000000000000040611324021725400171730ustar00rootroot00000000000000noinst_LIBRARIES = libtools.a libtools_HFILES = \ atrfartool.h \ atrneartool.h \ bgmovetool.h \ bgscaletool.h \ cubetool.h \ cubetoolwidget.h \ cylindertool.h \ cylindertoolwidget.h \ dragvertextool.h \ ellipsetool.h \ ellipsetoolwidget.h \ extrudetool.h \ jointtool.h \ pointtool.h \ projtool.h \ movetool.h \ polytool.h \ polytoolwidget.h \ projtoolwidget.h \ rectangletool.h \ rotatetool.h \ rotatetoolwidget.h \ scaletool.h \ scaletoolwidget.h \ selectbonetool.h \ selectpointtool.h \ selectprojtool.h \ selectconnectedtool.h \ selectfacetool.h \ selectfacetoolwidget.h \ selectgrouptool.h \ selectvertextool.h \ sheartool.h \ toolwidget.h \ torustool.h \ torustoolwidget.h \ vertextool.h libtools_MOC = \ cubetoolwidget.moc.cc \ cylindertoolwidget.moc.cc \ ellipsetoolwidget.moc.cc \ polytoolwidget.moc.cc \ projtoolwidget.moc.cc \ rotatetoolwidget.moc.cc \ scaletoolwidget.moc.cc \ toolwidget.moc.cc \ torustoolwidget.moc.cc \ selectfacetoolwidget.moc.cc BUILT_SOURCES = $(libtools_MOC) libtools_a_SOURCES = \ vertextool.cc \ atrfartool.cc \ atrneartool.cc \ bgmovetool.cc \ bgscaletool.cc \ cubetool.cc \ cubetoolwidget.cc \ cylindertool.cc \ cylindertoolwidget.cc \ dragvertextool.cc \ ellipsetool.cc \ ellipsetoolwidget.cc \ extrudetool.cc \ polytool.cc \ polytoolwidget.cc \ jointtool.cc \ pointtool.cc \ projtool.cc \ projtoolwidget.cc \ movetool.cc \ rotatetool.cc \ rotatetoolwidget.cc \ scaletool.cc \ scaletoolwidget.cc \ torustoolwidget.cc \ selectvertextool.cc \ selectconnectedtool.cc \ selectfacetool.cc \ selectfacetoolwidget.cc \ selectgrouptool.cc \ selectbonetool.cc \ selectpointtool.cc \ selectprojtool.cc \ sheartool.cc \ rectangletool.cc \ toolwidget.cc \ torustool.cc \ $(libtools_MOC) \ $(libtools_HFILES) AM_CPPFLAGS = $(CORE_PROFILE) $(COVFLAGS) -Wall -I../libmm3d -I../mm3dcore -I../depui -I../qtui -I../implui -I../ -DMM3D_EDIT $(all_includes) $(QT_CXXFLAGS) $(LUALIB_CCFLAGS) $(GL_CFLAGS) %.moc.cc: %.h $(QT_MOC) -o $@ $< CLEANFILES = $(libtools_MOC) *.gcno *.gcda mm3d-master/src/tools/atrfartool.cc000066400000000000000000000075721324021725400176350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "atrfartool.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "pixmap/atrfartool.xpm" #include "glmath.h" #include #include #include AttractFarTool::AttractFarTool() { } AttractFarTool::~AttractFarTool() { } const char * AttractFarTool::getPath() { return TOOLS_ATTRACT_MENU; } const char * AttractFarTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Attract Far" ); } bool AttractFarTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void AttractFarTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_positionCoords.clear(); Model * model = parent->getModel(); list positions; model->getSelectedPositions( positions ); m_positionCoords.clear(); makeToolCoordList( parent, m_positionCoords, positions ); ToolCoordList::iterator it; bool firstSet = false; double curX = 0; double curY = 0; parent->getParentXYValue( x, y, curX, curY, true ); for ( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { (*it).dist = distance( curX, curY, (*it).oldCoords[0], (*it).oldCoords[1] ); // update range if ( !firstSet ) { m_minDistance = (*it).dist; m_maxDistance = (*it).dist; firstSet = true; } else { if ( (*it).dist < m_minDistance ) { m_minDistance = (*it).dist; } if ( (*it).dist > m_maxDistance ) { m_maxDistance = (*it).dist; } } } m_startX = curX; m_startY = curY; model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Attracting far selected primitives" ).toUtf8() ); } void AttractFarTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); double curX = 0; double curY = 0; parent->getParentXYValue( x, y, curX, curY ); double lengthX = curX - m_startX; double lengthY = curY - m_startY; ToolCoordList::iterator it; for( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { double x = (*it).oldCoords[0]; double y = (*it).oldCoords[1]; double z = (*it).newCoords[2]; if ( (m_maxDistance - m_minDistance) >= 0.00001f ) { x += (lengthX * ( ((*it).dist - m_minDistance) / (m_maxDistance - m_minDistance) ) ); y += (lengthY * ( ((*it).dist - m_minDistance) / (m_maxDistance - m_minDistance) ) ); } else { x += lengthX; y += lengthY; } movePosition( parent, (*it).pos, x, y, z ); } parent->updateAllViews(); } void AttractFarTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Attract far complete" ).toUtf8() ); } const char ** AttractFarTool::getPixmap() { return (const char **) atrfartool_xpm; } double AttractFarTool::max( double a, double b ) { return ( a > b ) ? a : b; } mm3d-master/src/tools/atrfartool.h000066400000000000000000000034461324021725400174730ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ATRFARTOOL_H #define __ATRFARTOOL_H #include "tool.h" #include "model.h" #include using std::list; class AttractFarTool : public Tool { public: AttractFarTool(); virtual ~AttractFarTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); double min( double a, double b ); double max( double a, double b ); protected: double m_minDistance; double m_maxDistance; double m_startX; double m_startY; ToolCoordList m_positionCoords; }; #endif // __ATRFARTOOL_H mm3d-master/src/tools/atrneartool.cc000066400000000000000000000076321324021725400200070ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "atrneartool.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "pixmap/atrneartool.xpm" #include "glmath.h" #include #include #include AttractNearTool::AttractNearTool() { } AttractNearTool::~AttractNearTool() { } const char * AttractNearTool::getPath() { return TOOLS_ATTRACT_MENU; } const char * AttractNearTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Attract Near" ); } bool AttractNearTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void AttractNearTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_positionCoords.clear(); Model * model = parent->getModel(); list positions; model->getSelectedPositions( positions ); m_positionCoords.clear(); makeToolCoordList( parent, m_positionCoords, positions ); ToolCoordList::iterator it; bool firstSet = false; double curX = 0; double curY = 0; parent->getParentXYValue( x, y, curX, curY, true ); for ( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { (*it).dist = distance( curX, curY, (*it).oldCoords[0], (*it).oldCoords[1] ); // update range if ( !firstSet ) { m_minDistance = (*it).dist; m_maxDistance = (*it).dist; firstSet = true; } else { if ( (*it).dist < m_minDistance ) { m_minDistance = (*it).dist; } if ( (*it).dist > m_maxDistance ) { m_maxDistance = (*it).dist; } } } m_startX = curX; m_startY = curY; model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Attracting near selected primitives" ).toUtf8() ); } void AttractNearTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); double curX = 0; double curY = 0; parent->getParentXYValue( x, y, curX, curY ); double lengthX = curX - m_startX; double lengthY = curY - m_startY; ToolCoordList::iterator it; for( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { double x = (*it).oldCoords[0]; double y = (*it).oldCoords[1]; double z = (*it).newCoords[2]; if ( (m_maxDistance - m_minDistance) >= 0.00001f ) { x += (lengthX * ( 1.0 - ((*it).dist - m_minDistance) / (m_maxDistance - m_minDistance) ) ); y += (lengthY * ( 1.0 - ((*it).dist - m_minDistance) / (m_maxDistance - m_minDistance) ) ); } else { x += lengthX; y += lengthY; } movePosition( parent, (*it).pos, x, y, z ); } parent->updateAllViews(); } void AttractNearTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Attract near complete" ).toUtf8() ); } const char ** AttractNearTool::getPixmap() { return (const char **) atrneartool_xpm; } double AttractNearTool::max( double a, double b ) { return ( a > b ) ? a : b; } mm3d-master/src/tools/atrneartool.h000066400000000000000000000034541324021725400176470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ATRNEARTOOL_H #define __ATRNEARTOOL_H #include "tool.h" #include "model.h" #include using std::list; class AttractNearTool : public Tool { public: AttractNearTool(); virtual ~AttractNearTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); double min( double a, double b ); double max( double a, double b ); protected: double m_minDistance; double m_maxDistance; double m_startX; double m_startY; ToolCoordList m_positionCoords; }; #endif // __ATRNEARTOOL_H mm3d-master/src/tools/bgmovetool.cc000066400000000000000000000065751324021725400176370ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "bgmovetool.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "glmath.h" #include "pixmap/bgmovetool.xpm" #include BgMoveTool::BgMoveTool() { } BgMoveTool::~BgMoveTool() { } const char * BgMoveTool::getPath() { return TOOLS_BACKGROUND_MENU; } const char * BgMoveTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Move Background Image" ); } bool BgMoveTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void BgMoveTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); Model * model = parent->getModel(); int index = (int) parent->getViewDirection() - 1; if ( index >= 0 ) { m_lastX = 0; m_lastX = 0; m_lastX = 0; parent->getXValue( x, y, &m_lastX ); parent->getYValue( x, y, &m_lastY ); parent->getZValue( x, y, &m_lastZ ); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Moving background image" ).toUtf8() ); } else { model_status( model, StatusError, STATUSTIME_SHORT, qApp->translate( "Tool", "Cannot move background from 3D view" ).toUtf8() ); } } void BgMoveTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); Model * model = parent->getModel(); int index = (int) parent->getViewDirection() - 1; if ( index >= 0 ) { float cenX = 0.0f; float cenY = 0.0f; float cenZ = 0.0f; double newX = 0.0f; double newY = 0.0f; double newZ = 0.0f; parent->getXValue( x, y, &newX ); parent->getYValue( x, y, &newY ); parent->getZValue( x, y, &newZ ); model->getBackgroundCenter( index, cenX, cenY, cenZ ); cenX += (newX - m_lastX); cenY += (newY - m_lastY); cenZ += (newZ - m_lastZ); model->setBackgroundCenter( index, cenX, cenY, cenZ ); m_lastX = newX; m_lastY = newY; m_lastZ = newZ; } parent->updateAllViews(); } void BgMoveTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Background move complete" ).toUtf8() ); } const char ** BgMoveTool::getPixmap() { return (const char **) bgmovetool_xpm; } void BgMoveTool::activated( int arg, Model * model, QMainWindow * mainwin ) { model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Move background image" ).toUtf8() ); } void BgMoveTool::deactivated() { //m_widget->close(); } mm3d-master/src/tools/bgmovetool.h000066400000000000000000000033211324021725400174630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BGMOVETOOL_H #define __BGMOVETOOL_H #include "tool.h" class BgMoveTool : public Tool { public: BgMoveTool(); virtual ~BgMoveTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: double m_lastX; double m_lastY; double m_lastZ; //BgMoveToolWidget * m_widget; }; #endif // __BGMOVETOOL_H mm3d-master/src/tools/bgscaletool.cc000066400000000000000000000102261324021725400177440ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "bgscaletool.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "glmath.h" #include "pixmap/bgscaletool.xpm" #include BgScaleTool::BgScaleTool() { } BgScaleTool::~BgScaleTool() { } const char * BgScaleTool::getPath() { return TOOLS_BACKGROUND_MENU; } const char * BgScaleTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Scale Background Image" ); } bool BgScaleTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void BgScaleTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); Model * model = parent->getModel(); int index = (int) parent->getViewDirection() - 1; if ( index >= 0 ) { float cenX = 0.0f; float cenY = 0.0f; float cenZ = 0.0f; m_x = 0.0f; m_y = 0.0f; m_z = 0.0f; parent->getXValue( x, y, &m_x ); parent->getYValue( x, y, &m_y ); parent->getZValue( x, y, &m_z ); float tempX = m_x; float tempY = m_y; float tempZ = m_z; model->getBackgroundCenter( index, cenX, cenY, cenZ ); m_startScale = model->getBackgroundScale( index ); m_startLength = distance( cenX, cenY, cenZ, tempX, tempY, tempZ ); if ( m_startLength < 0.0001f ) { m_startLength = 0.0001f; } log_debug( "center (%f,%f,%f) mouse (%f,%f,%f)\n", cenX, cenY, cenZ, tempX, tempY, tempZ ); log_debug( "starting background scale with length %f, scale %f\n", m_startLength, m_startScale ); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Scaling background image" ).toUtf8() ); } else { model_status( model, StatusError, STATUSTIME_SHORT, qApp->translate( "Tool", "Cannot scale background from 3D view" ).toUtf8() ); } } void BgScaleTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); Model * model = parent->getModel(); int index = (int) parent->getViewDirection() - 1; if ( index >= 0 ) { float cenX = 0.0f; float cenY = 0.0f; float cenZ = 0.0f; double newX = 0.0f; double newY = 0.0f; double newZ = 0.0f; parent->getXValue( x, y, &newX ); parent->getYValue( x, y, &newY ); parent->getZValue( x, y, &newZ ); float tempX = newX; float tempY = newY; float tempZ = newZ; model->getBackgroundCenter( index, cenX, cenY, cenZ ); float length = distance( cenX, cenY, cenZ, tempX, tempY, tempZ ); float scale = length * (m_startScale / m_startLength ); log_debug( "scale with length %f, to scale %f\n", length, scale ); model->setBackgroundScale( index, scale ); } parent->updateAllViews(); } void BgScaleTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Background scale complete" ).toUtf8() ); } const char ** BgScaleTool::getPixmap() { return (const char **) bgscaletool_xpm; } void BgScaleTool::activated( int arg, Model * model, QMainWindow * mainwin ) { model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Scale background image" ).toUtf8() ); } void BgScaleTool::deactivated() { //m_widget->close(); } mm3d-master/src/tools/bgscaletool.h000066400000000000000000000034041324021725400176060ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __BGSCALETOOL_H #define __BGSCALETOOL_H #include "tool.h" class BgScaleTool : public Tool { public: BgScaleTool(); virtual ~BgScaleTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: double m_x; double m_y; double m_z; double m_startLength; double m_startScale; //BgScaleToolWidget * m_widget; }; #endif // __BGSCALETOOL_H mm3d-master/src/tools/cubetool.cc000066400000000000000000000177611324021725400172750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cubetool.h" #include "pixmap/cubetool.xpm" #include "model.h" #include "weld.h" #include "modelstatus.h" #include "log.h" #include #include #include using std::vector; static void _cubify( bool isCube, double & coord, double & diff_d, double & diff_s1, double & diff_s2 ) { if ( isCube ) { if ( fabs(diff_s1) > fabs(diff_s2) ) { if ( (diff_s1 < 0 && diff_s2 > 0) || (diff_s1 > 0 && diff_s2 < 0 ) ) { diff_s2 = -diff_s1; } else { diff_s2 = diff_s1; } } else { if ( (diff_s1 < 0 && diff_s2 > 0) || (diff_s1 > 0 && diff_s2 < 0 ) ) { diff_s1 = -diff_s2; } else { diff_s1 = diff_s2; } } } if ( fabs(diff_s1) < fabs(diff_s2) ) { coord = fabs(diff_s1/2.0); diff_d = -fabs(diff_s1); } else { coord = fabs(diff_s1/2.0); diff_d = -fabs(diff_s1); } } CubeTool::CubeTool() : m_tracking( false ), m_parent( NULL ) { } CubeTool::~CubeTool() { } void CubeTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( !m_tracking ) { m_parent = parent; // Keep track of which parent we're serving m_tracking = true; m_invertedNormals = false; m_x1 = 0.0; m_y1 = 0.0; m_z1 = 0.0; parent->getParentXYValue( x, y, m_x1, m_y1, true ); Model * model = parent->getModel(); model->unselectAll(); double x1 = 0.0; double y1 = 0.0; double x2 = 0.0; double y2 = 0.0; double z = 0.0; int xindex = 0; int yindex = 1; int zindex = 2; for ( unsigned side = 0; side < 6; side++ ) { if ( side & 1 ) { x1 = 1.0; x2 = 0.0; y1 = 1.0; y2 = 0.0; z = 1.0; } else { x1 = 0.0; x2 = 1.0; y1 = 1.0; y2 = 0.0; z = 0.0; } switch ( side ) { case 0: case 1: xindex = 0; yindex = 1; zindex = 2; break; case 2: case 3: xindex = 2; yindex = 1; zindex = 0; break; case 4: case 5: xindex = 0; yindex = 2; zindex = 1; break; default: break; } double coord[3]; for ( unsigned y = 0; y <= m_segments; y++ ) { for ( unsigned x = 0; x <= m_segments; x++ ) { coord[xindex] = x1 + ((x2 - x1) * (double) x / (double) m_segments); coord[yindex] = y1 + ((y2 - y1) * (double) y / (double) m_segments); coord[zindex] = z; ToolCoordT tc = addPosition( parent, Model::PT_Vertex, NULL, coord[0], coord[1], coord[2] ); log_debug( "adding vertex %d at %f,%f,%f\n", tc.pos.index, tc.oldCoords[0], tc.oldCoords[1], tc.oldCoords[2] ); m_vertices.push_back( tc ); } if ( y > 0 ) { int row1 = m_vertices.size() - (m_segments + 1) * 2; int row2 = m_vertices.size() - (m_segments + 1); for ( unsigned x = 0; x < m_segments; x++ ) { log_debug( "%d,%d,%d,%d\n", row1 + x, row1 + x + 1, row2 + x, row2 + x + 1 ); int t1 = model->addTriangle( m_vertices[ row2 + x ].pos.index, m_vertices[ row1 + x + 1].pos.index, m_vertices[ row1 + x ].pos.index ); int t2 = model->addTriangle( m_vertices[ row2 + x ].pos.index, m_vertices[ row2 + x + 1].pos.index, m_vertices[ row1 + x + 1].pos.index ); m_triangles.push_back( t1 ); m_triangles.push_back( t2 ); if ( side >= 2 ) { model->invertNormals( t1 ); model->invertNormals( t2 ); } } } } } unsigned count = m_vertices.size(); for ( unsigned sv = 0; sv < count; sv++ ) { model->selectVertex( m_vertices[sv].pos.index ); } updateVertexCoords( parent, m_x1, m_y1, m_z1, m_x1, m_y1, m_z1 ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Cube created" ).toUtf8() ); } } void CubeTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( parent != m_parent ) { log_error( "Can't serve two parents at once\n" ); } if ( m_tracking ) { m_tracking = false; double x2 = 0.0; double y2 = 0.0; double z2 = 0.0; parent->getParentXYValue( x, y, x2, y2 ); updateVertexCoords( parent, m_x1, m_y1, m_z1, x2, y2, z2 ); weldSelectedVertices( parent->getModel() ); parent->updateAllViews(); m_vertices.clear(); m_triangles.clear(); } } void CubeTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( parent != m_parent ) { log_error( "Can't serve two parents at once\n" ); } if ( m_tracking ) { double x2 = 0.0; double y2 = 0.0; double z2 = 0.0; parent->getParentXYValue( x, y, x2, y2 ); updateVertexCoords( parent, m_x1, m_y1, m_z1, x2, y2, z2 ); parent->updateAllViews(); } } void CubeTool::updateVertexCoords( Parent * parent, double x1, double y1, double z1, double x2, double y2, double z2 ) { Model * model = parent->getModel(); bool invert = false; double xdiff = x2 - x1; double ydiff = y2 - y1; double zdiff = z2 - z1; _cubify( m_isCube, z1, zdiff, xdiff, ydiff ); if ( y1 < y2 ) { invert = !invert; } if ( x2 > x1 ) { invert = !invert; } ToolCoordList::iterator it; for ( it = m_vertices.begin(); it != m_vertices.end(); it++ ) { movePosition( parent, (*it).pos, (*it).oldCoords[0]*xdiff + x1, (*it).oldCoords[1]*ydiff + y1, (*it).oldCoords[2]*zdiff + z1 ); } if ( invert != m_invertedNormals ) { unsigned count = m_triangles.size(); for ( unsigned t = 0; t < count; t++ ) { model->invertNormals( m_triangles[t] ); } m_invertedNormals = invert; } } void CubeTool::activated( int arg, Model * model, QMainWindow * mainwin ) { m_widget = new CubeToolWidget( this, mainwin ); m_widget->show(); } void CubeTool::deactivated() { m_widget->close(); } const char ** CubeTool::getPixmap() { return (const char **) cubetool_xpm; } void CubeTool::setCubeValue( bool newValue ) { m_isCube = newValue; log_debug( "isCube = %s\n", newValue ? "true" : "false" ); } void CubeTool::setSegmentValue( int newValue ) { if ( newValue >= 1 ) { m_segments = newValue; } } const char * CubeTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Cube" ); } mm3d-master/src/tools/cubetool.h000066400000000000000000000042041324021725400171230ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CUBETOOL_H #define __CUBETOOL_H #include "tool.h" #include "cubetoolwidget.h" #include class CubeTool : public ::Tool, public CubeToolWidget::Observer { public: CubeTool(); virtual ~CubeTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool isCreation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // Observer methods void setCubeValue( bool newValue ); void setSegmentValue( int newValue ); protected: bool m_tracking; Parent * m_parent; CubeToolWidget * m_widget; bool m_isCube; unsigned m_segments; void updateVertexCoords( Parent *, double x1, double y1, double z1, double x2, double y2, double z2 ); ToolCoordList m_vertices; std::vector m_triangles; double m_x1; double m_y1; double m_z1; bool m_invertedNormals; }; #endif // __CUBETOOL_H mm3d-master/src/tools/cubetoolwidget.cc000066400000000000000000000060421324021725400204670ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cubetoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include #include #include CubeToolWidget::CubeToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget( parent ), m_observer( observer ) { const int DEFAULT_SEGMENT = 1; const bool DEFAULT_CUBE = false; m_layout = boxLayout(); m_cubeLabel = new QLabel( tr("Cube"), mainWidget() ); m_layout->addWidget( m_cubeLabel ); m_cubeValue = new QCheckBox( mainWidget() ); m_layout->addWidget( m_cubeValue ); bool isCube = DEFAULT_CUBE; if ( g_prefs.exists( "ui_cubetool_iscube" ) ) { isCube = (g_prefs( "ui_cubetool_iscube" ).intValue() != 0) ? true : false; } m_cubeValue->setChecked( isCube ); m_segmentLabel = new QLabel( tr("Segment"), mainWidget() ); m_layout->addWidget( m_segmentLabel ); m_segmentValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_segmentValue ); m_segmentValue->setMinimum( 1 ); m_segmentValue->setMaximum( 25 ); int segmentVal = DEFAULT_SEGMENT; if ( g_prefs.exists( "ui_cubetool_segment" ) ) { int val = g_prefs( "ui_cubetool_segment" ).intValue(); if ( val >= 1 && val <= 25 ) { segmentVal = val; } } m_segmentValue->setValue( segmentVal ); m_layout->addStretch(); connect( m_cubeValue, SIGNAL(toggled(bool)), this, SLOT(cubeValueChanged(bool)) ); connect( m_segmentValue, SIGNAL(valueChanged(int)), this, SLOT(segmentValueChanged(int)) ); m_cubeLabel->show(); m_cubeValue->show(); m_segmentLabel->show(); m_segmentValue->show(); cubeValueChanged( isCube ); segmentValueChanged( segmentVal ); m_layout->addStretch(); } CubeToolWidget::~CubeToolWidget() { } void CubeToolWidget::segmentValueChanged( int newValue ) { g_prefs( "ui_cubetool_segment" ) = newValue; m_observer->setSegmentValue( newValue ); } void CubeToolWidget::cubeValueChanged( bool newValue ) { g_prefs( "ui_cubetool_iscube" ) = newValue ? 1 : 0; m_observer->setCubeValue( newValue ); } mm3d-master/src/tools/cubetoolwidget.h000066400000000000000000000034751324021725400203400ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CUBETOOLWIDGET_H #define __CUBETOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QCheckBox; class QLabel; #include "toolwidget.h" class CubeToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setCubeValue( bool newValue ) = 0; virtual void setSegmentValue( int newValue ) = 0; }; CubeToolWidget( Observer * observer, QMainWindow * parent ); virtual ~CubeToolWidget(); public slots: void cubeValueChanged( bool cube ); void segmentValueChanged( int newValue ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_cubeLabel; QCheckBox * m_cubeValue; QLabel * m_segmentLabel; QSpinBox * m_segmentValue; }; #endif // __CUBETOOLWIDGET_H mm3d-master/src/tools/cylindertool.cc000066400000000000000000000222251324021725400201570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cylindertool.h" #include "pixmap/cylindertool.xpm" #include "model.h" #include "glmath.h" #include "log.h" #include "modelstatus.h" #include #include #include using std::vector; using std::list; CylinderTool::CylinderTool() : m_segments( 1 ), m_sides( 8 ), m_inverted( false ) { } CylinderTool::~CylinderTool() { } void CylinderTool::activated( int arg, Model * model, QMainWindow * mainwin ) { log_debug( "cylinder activated\n" ); m_widget = new CylinderToolWidget( this, mainwin ); m_widget->show(); } void CylinderTool::deactivated() { m_widget->close(); } void CylinderTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); model->unselectAll(); double pos[3] = {0,0,0}; double rad[3] = {0,0,0}; m_inverted = false; parent->getParentXYValue( x, y, pos[0], pos[1], true ); m_startX = pos[0]; m_startY = pos[1]; unsigned triStart = model->getTriangleCount(); unsigned points = m_sides; ToolCoordT ev; unsigned s; unsigned r; // Create external cylinder for ( s = 0; s <= m_segments; s++ ) { double scale = (double) m_scale / 100.0; scale = (double) m_scale / 100.0; scale = (1.0 - scale) * ((double) s / (double) m_segments) //* (sqrt( 10000.0 * (double) s / (double) m_segments ) / 100.0) //* ( sin( ((double) s / (double) m_segments) * PI / 2.0 ) ) + scale; for ( r = 0; r < points; r++ ) { double vx = (double) s / (double) (m_segments); double vy = cos( ((double) r / (double) points) * PI * 2.0 ) * scale; double vz = sin( ((double) r / (double) points) * PI * 2.0 ) * scale; ev = addPosition( parent, Model::PT_Vertex, NULL, vx, vy, vz ); m_vertices.push_back( ev ); } if ( s > 0 ) { for ( r = 0; r < points; r++ ) { unsigned next = r + 1; if ( next >= points ) { next = 0; } model->addTriangle( m_vertices[((s-1)*points) + r].pos.index, m_vertices[ ((s-1)*points) + next].pos.index, m_vertices[ (s*points) + r ].pos.index ); model->addTriangle( m_vertices[((s-1)*points) + next].pos.index, m_vertices[ (s*points) + next].pos.index, m_vertices[ (s*points) + r ].pos.index ); } } } unsigned off = m_vertices.size(); // Create internal cylinder if ( m_width < 100 ) { double rad = 1.0 - (double) m_width / 100.0; if ( rad > 0.999 ) { rad = 0.999; } for ( s = 0; s <= m_segments; s++ ) { double scale = (double) m_scale / 100.0; scale = (1.0 - scale) * ((double) s / (double) m_segments) + scale; for ( r = 0; r < points; r++ ) { double vx = (double) s / (double) (m_segments); double vy = cos( ((double) r / (double) points) * PI * 2.0 ) * rad * scale; double vz = sin( ((double) r / (double) points) * PI * 2.0 ) * rad * scale; ev = addPosition( parent, Model::PT_Vertex, NULL, vx, vy, vz ); m_vertices.push_back( ev ); } if ( s > 0 ) { for ( r = 0; r < points; r++ ) { unsigned next = r + 1; if ( next >= points ) { next = 0; } model->addTriangle( m_vertices[ off + ((s-1)*points) + next ].pos.index, m_vertices[ off + ((s-1)*points) + r ].pos.index, m_vertices[ off + (s*points) + r ].pos.index ); model->addTriangle( m_vertices[ off + ((s-1)*points) + next ].pos.index, m_vertices[ off + (s*points) + r ].pos.index, m_vertices[ off + (s*points) + next ].pos.index ); } } } // Add ends unsigned off2 = m_vertices.size() - points; for ( r = 0; r < points; r++ ) { unsigned next = r + 1; if ( next >= points ) { next = 0; } model->addTriangle( m_vertices[ next ].pos.index, m_vertices[ r ].pos.index, m_vertices[ off + r ].pos.index ); model->addTriangle( m_vertices[ next ].pos.index, m_vertices[ off + r ].pos.index, m_vertices[ off + next ].pos.index ); model->addTriangle( m_vertices[ (off - points) + r ].pos.index, m_vertices[ (off - points) + next ].pos.index, m_vertices[ off2 + r ].pos.index ); model->addTriangle( m_vertices[ (off - points) + next ].pos.index, m_vertices[ off2 + next ].pos.index, m_vertices[ off2 + r ].pos.index ); } } else // No internal cylinder { off = m_vertices.size() - points; // Add ends ev = addPosition( parent, Model::PT_Vertex, NULL, 0, 0, 0 ); for ( r = 0; r < points; r++ ) { unsigned next = r + 1; if ( next >= points ) { next = 0; } model->addTriangle( ev.pos.index, m_vertices[ next ].pos.index, m_vertices[ r ].pos.index ); } m_vertices.push_back( ev ); ev = addPosition( parent, Model::PT_Vertex, NULL, 1, 0, 0 ); m_vertices.push_back( ev ); for ( r = 0; r < points; r++ ) { unsigned next = r + 1; if ( next >= points ) { next = 0; } model->addTriangle( ev.pos.index, m_vertices[ off + r].pos.index, m_vertices[ off + next].pos.index ); } m_vertices.push_back( ev ); } unsigned triEnd = model->getTriangleCount(); for ( unsigned t = triStart; t < triEnd; t++ ) { model->selectTriangle( t ); } updateVertexCoords( parent, pos[0], pos[1], pos[2], rad[0], rad[1], rad[2] ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Cylinder created" ).toUtf8() ); } void CylinderTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { m_vertices.clear(); } void CylinderTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); double pos[3] = {0,0,0}; double rad[3] = {0,0,0}; parent->getParentXYValue( x, y, pos[0], pos[1] ); bool doInvert = false; rad[0] = (pos[0] - m_startX); rad[1] = fabs(m_startY - pos[1]) / 2; rad[2] = fabs(m_startY - pos[1]) / 2; pos[0] = m_startX; pos[1] = (pos[1] + m_startY) / 2; pos[2] = 0; if ( rad[0] < 0.0 && m_inverted == false ) { doInvert = true; } else if ( rad[0] >= 0.0 && m_inverted == true ) { doInvert = true; } if ( doInvert ) { m_inverted = !m_inverted; list selectedList; model->getSelectedTriangles( selectedList ); list::iterator it; for ( it = selectedList.begin(); it != selectedList.end(); it++ ) { model->invertNormals( *it ); } } updateVertexCoords( parent, pos[0], pos[1], pos[2], rad[0], rad[1], rad[2] ); parent->updateAllViews(); } const char ** CylinderTool::getPixmap() { return (const char **) cylindertool_xpm; } void CylinderTool::updateVertexCoords( Tool::Parent * parent, double x, double y, double z, double xrad, double yrad, double zrad ) { ToolCoordList::iterator it; for ( it = m_vertices.begin(); it != m_vertices.end(); it++ ) { movePosition( parent, (*it).pos, (*it).oldCoords[0]*xrad + x, (*it).oldCoords[1]*yrad + y, (*it).oldCoords[2]*zrad + z ); } } void CylinderTool::setSegmentsValue( int newValue ) { log_debug( "segments: %d\n", newValue ); m_segments = newValue; } void CylinderTool::setSidesValue( int newValue ) { log_debug( "sides: %d\n", newValue ); m_sides = newValue; } void CylinderTool::setWidthValue( int newValue ) { log_debug( "width: %d\n", newValue ); m_width = newValue; } void CylinderTool::setScaleValue( int newValue ) { log_debug( "scale: %d\n", newValue ); m_scale = newValue; } void CylinderTool::setShapeValue( int newValue ) { log_debug( "shape: %d\n", newValue ); m_shape = newValue; } const char * CylinderTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Cylinder" ); } mm3d-master/src/tools/cylindertool.h000066400000000000000000000043751324021725400200270ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CYLINDERTOOL_H #define __CYLINDERTOOL_H #include "tool.h" #include "cylindertoolwidget.h" #include class CylinderTool : public Tool, public CylinderToolWidget::Observer { public: CylinderTool(); virtual ~CylinderTool(); int getToolCount() { return 1; }; const char * getName( int arg ); void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // CylinderToolWidget::Observer void setSegmentsValue( int newValue ); void setSidesValue( int newValue ); void setWidthValue( int newValue ); void setScaleValue( int newValue ); void setShapeValue( int newValue ); protected: void updateVertexCoords( Tool::Parent *, double x, double y, double z, double xrad, double yrad, double zrad ); CylinderToolWidget * m_widget; unsigned m_segments; unsigned m_sides; unsigned m_width; unsigned m_scale; unsigned m_shape; bool m_inverted; ToolCoordList m_vertices; double m_startX; double m_startY; }; #endif // __CYLINDERTOOL_H mm3d-master/src/tools/cylindertoolwidget.cc000066400000000000000000000133261324021725400213650ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "cylindertoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include CylinderToolWidget::CylinderToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_SEGMENTS = 4; const int DEFAULT_SIDES = 8; const int DEFAULT_WIDTH = 100; const int DEFAULT_SCALE = 100; //const int DEFAULT_SHAPE = 10; m_layout = boxLayout(); m_segmentsLabel = new QLabel( tr("Segments"), mainWidget() ); m_layout->addWidget( m_segmentsLabel ); m_segmentsValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_segmentsValue ); m_segmentsValue->setMinimum( 1 ); m_segmentsValue->setMaximum( 100 ); int segmentsVal = DEFAULT_SEGMENTS; if ( g_prefs.exists( "ui_cylindertool_segments" ) ) { int val = g_prefs( "ui_cylindertool_segments" ).intValue(); if ( val >= 1 && val <= 100 ) { segmentsVal = val; } } m_segmentsValue->setValue( segmentsVal ); m_sidesLabel = new QLabel( tr("Sides"), mainWidget() ); m_layout->addWidget( m_sidesLabel ); m_sidesValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_sidesValue ); m_sidesValue->setMinimum( 3 ); m_sidesValue->setMaximum( 100 ); int sidesVal = DEFAULT_SIDES; if ( g_prefs.exists( "ui_cylindertool_sides" ) ) { int val = g_prefs( "ui_cylindertool_sides" ).intValue(); if ( val >= 3 && val <= 100 ) { sidesVal = val; } } m_sidesValue->setValue( sidesVal ); m_widthLabel = new QLabel( tr("Width"), mainWidget() ); m_layout->addWidget( m_widthLabel ); m_widthValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_widthValue ); m_widthValue->setMinimum( 0 ); m_widthValue->setMaximum( 100 ); int widthVal = DEFAULT_WIDTH; if ( g_prefs.exists( "ui_cylindertool_width" ) ) { int val = g_prefs( "ui_cylindertool_width" ).intValue(); if ( val >= 0 && val <= 100 ) { widthVal = val; } } m_widthValue->setValue( widthVal ); m_scaleLabel = new QLabel( tr("Scale"), mainWidget() ); m_layout->addWidget( m_scaleLabel ); m_scaleValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_scaleValue ); m_scaleValue->setMinimum( 0 ); m_scaleValue->setMaximum( 100 ); int scaleVal = DEFAULT_SCALE; if ( g_prefs.exists( "ui_cylindertool_scale" ) ) { int val = g_prefs( "ui_cylindertool_scale" ).intValue(); if ( val >= 0 && val <= 100 ) { scaleVal = val; } } m_scaleValue->setValue( scaleVal ); /* m_shapeLabel = new QLabel( "Shape", mainWidget() ); m_layout->addWidget( m_shapeLabel ); m_shapeValue = new QSlider( Qt::Horizontal, mainWidget() ); m_layout->addWidget( m_shapeValue ); m_shapeValue->setMinimumWidth( 64 ); m_shapeValue->setMinimum( 0 ); m_shapeValue->setMaximum( DEFAULT_SHAPE * 2 ); m_shapeValue->setValue( DEFAULT_SHAPE ); m_shapeValue->setTickInterval( DEFAULT_SHAPE / 2); m_shapeValue->setTickmarks( QSlider::Below ); */ m_layout->addStretch(); connect( m_segmentsValue, SIGNAL(valueChanged(int)), this, SLOT(segmentsValueChanged(int)) ); connect( m_sidesValue, SIGNAL(valueChanged(int)), this, SLOT(sidesValueChanged(int)) ); connect( m_widthValue, SIGNAL(valueChanged(int)), this, SLOT(widthValueChanged(int)) ); connect( m_scaleValue, SIGNAL(valueChanged(int)), this, SLOT(scaleValueChanged(int)) ); //connect( m_shapeValue, SIGNAL(valueChanged(int)), this, SLOT(shapeValueChanged(int)) ); m_segmentsLabel->show(); m_segmentsValue->show(); m_sidesLabel->show(); m_sidesValue->show(); m_widthLabel->show(); m_widthValue->show(); m_scaleLabel->show(); m_scaleValue->show(); //m_shapeLabel->hide(); //m_shapeValue->hide(); segmentsValueChanged( segmentsVal ); sidesValueChanged( sidesVal ); widthValueChanged( widthVal ); scaleValueChanged( scaleVal ); //shapeValueChanged( DEFAULT_SHAPE ); } CylinderToolWidget::~CylinderToolWidget() { } void CylinderToolWidget::segmentsValueChanged( int newValue ) { g_prefs( "ui_cylindertool_segments" ) = newValue; m_observer->setSegmentsValue( newValue ); } void CylinderToolWidget::sidesValueChanged( int newValue ) { g_prefs( "ui_cylindertool_sides" ) = newValue; m_observer->setSidesValue( newValue ); } void CylinderToolWidget::widthValueChanged( int newValue ) { g_prefs( "ui_cylindertool_width" ) = newValue; m_observer->setWidthValue( newValue ); } void CylinderToolWidget::scaleValueChanged( int newValue ) { g_prefs( "ui_cylindertool_scale" ) = newValue; m_observer->setScaleValue( newValue ); } void CylinderToolWidget::shapeValueChanged( int newValue ) { m_observer->setShapeValue( newValue ); } mm3d-master/src/tools/cylindertoolwidget.h000066400000000000000000000045661324021725400212350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __CYLINDERTOOLWIDGET_H #define __CYLINDERTOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QSlider; class QLabel; #include "toolwidget.h" class CylinderToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setSegmentsValue( int newValue ) = 0; virtual void setSidesValue( int newValue ) = 0; virtual void setWidthValue( int newValue ) = 0; virtual void setScaleValue( int newValue ) = 0; virtual void setShapeValue( int newValue ) = 0; }; CylinderToolWidget( Observer * observer, QMainWindow * parent ); virtual ~CylinderToolWidget(); public slots: void segmentsValueChanged( int newValue ); void sidesValueChanged( int newValue ); void widthValueChanged( int newValue ); void scaleValueChanged( int newValue ); void shapeValueChanged( int newValue ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_segmentsLabel; QSpinBox * m_segmentsValue; QLabel * m_sidesLabel; QSpinBox * m_sidesValue; QLabel * m_widthLabel; QSpinBox * m_widthValue; QLabel * m_scaleLabel; QSpinBox * m_scaleValue; //QLabel * m_shapeLabel; //QSlider * m_shapeValue; }; #endif // __CYLINDERTOOLWIDGET_H mm3d-master/src/tools/dragvertextool.cc000066400000000000000000000137131324021725400205230ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "dragvertextool.h" #include "pixmap/dragvertextool.xpm" #include "glmath.h" #include "model.h" #include "modelstatus.h" #include #include #include #include "log.h" DragVertexTool::DragVertexTool() { } DragVertexTool::~DragVertexTool() { } void DragVertexTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); m_vertVectors.clear(); std::list vertices; model->getSelectedVertices( vertices ); if ( !vertices.empty() ) { m_vertId = vertices.front(); m_view = parent->getParentViewMatrix(); // model to viewport space m_inv = parent->getParentViewInverseMatrix(); // viewport to model space m_vertCoords[0] = 0; m_vertCoords[1] = 0; m_vertCoords[2] = 0; model->getVertexCoords( m_vertId, m_vertCoords ); log_debug( "vertex %d is at ( %f, %f, %f )\n", m_vertId, m_vertCoords[0], m_vertCoords[1], m_vertCoords[2] ); m_view.apply3x( m_vertCoords ); size_t tcount = model->getTriangleCount(); for ( size_t t = 0; t < tcount; t++ ) { int tv[3]; int i; bool match = false; for ( i = 0; i < 3; i++ ) { tv[i] = model->getTriangleVertex( t, i ); if ( tv[i] == m_vertId ) { // TODO: could find the same vertex multiple times if // edge belongs to more than one triangle, may want // to prevent that in the future match = true; } } if ( match ) { for ( i = 0; i < 3; i++ ) { if ( tv[i] != m_vertId ) { double c[3] = { 0, 0, 0 }; model->getVertexCoords( tv[i], c ); m_view.apply3x( c ); Vector v; v[0] = c[0] - m_vertCoords[0]; v[1] = c[1] - m_vertCoords[1]; v[2] = c[2] - m_vertCoords[2]; log_debug( "adding vector ( %f, %f, %f )\n", v[0], v[1], v[2] ); m_vertVectors.push_back( v ); } } } } model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Dragging selected vertex" ).toUtf8() ); } else { m_vertId = -1; model_status( parent->getModel(), StatusError, STATUSTIME_LONG, qApp->translate( "Tool", "Must a vertex selected" ).toUtf8() ); } } void DragVertexTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Drag complete" ).toUtf8() ); } void DragVertexTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { Matrix m; Vector newPos; parent->getParentXYValue( x, y, newPos[0], newPos[1] ); Model * model = parent->getModel(); log_debug( "pos is ( %f, %f, %f )\n", newPos[0], newPos[1], newPos[2] ); newPos[0] -= m_vertCoords[0]; newPos[1] -= m_vertCoords[1]; log_debug( "pos vector is ( %f, %f, %f )\n", newPos[0], newPos[1], newPos[2] ); double pscale = newPos.mag3(); newPos.normalize3(); log_debug( "mouse has moved %f units\n", pscale ); if ( !m_vertVectors.empty() && m_vertId >= 0 ) { Vector best = m_vertVectors.front(); double bestDist = 0.0; double ratio = 1.0; std::list< Vector >::iterator it; for ( it = m_vertVectors.begin(); it != m_vertVectors.end(); it++ ) { Vector vtry = (*it); vtry[2] = 0; double trylen = vtry.mag3(); vtry.normalize3(); double d = newPos.dot3( vtry ); log_debug( " dot3 is %f (%f, %f, %f)\n", d, vtry[0], vtry[1], vtry[2] ); if ( fabs( d ) > fabs( bestDist ) ) { bestDist = d; best = (*it); ratio = pscale / trylen; } } log_debug( "best vector is (%f, %f, %f)\n", best[0], best[1], best[2] ); best.scale3( bestDist * ratio ); log_debug( "best scaled is (%f, %f, %f)\n", best[0], best[1], best[2] ); best[0] += m_vertCoords[0]; best[1] += m_vertCoords[1]; best[2] += m_vertCoords[2]; log_debug( "best sum is (%f, %f, %f)\n", best[0], best[1], best[2] ); m_inv.apply3x( best ); log_debug( "best applied is (%f, %f, %f)\n", best[0], best[1], best[2] ); model->moveVertex( m_vertId, best[0], best[1], best[2] ); } parent->updateAllViews(); } const char ** DragVertexTool::getPixmap() { return (const char **) dragvertextool_xpm; } void DragVertexTool::activated( int argc, Model * model, QMainWindow * mainwin ) { //model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Tip: Hold shift to restrict movement to one dimension" ).toUtf8() ); } const char * DragVertexTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Drag Vertex on Edge" ); } mm3d-master/src/tools/dragvertextool.h000066400000000000000000000035311324021725400203620ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __DRAGVERTEXTOOL_H #define __DRAGVERTEXTOOL_H #include "tool.h" #include "glmath.h" #include #include class DragVertexTool: public Tool { public: DragVertexTool(); virtual ~DragVertexTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_M; return true; }; void activated( int argc, Model * model, QMainWindow * mainwin ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: Matrix m_view; Matrix m_inv; int m_vertId; double m_vertCoords[3]; std::list< Vector > m_vertVectors; }; #endif // __DRAGVERTEXTOOL_H mm3d-master/src/tools/ellipsetool.cc000066400000000000000000000157661324021725400200170ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "ellipsetool.h" #include "pixmap/ellipsetool.xpm" #include "model.h" #include "glmath.h" #include "log.h" #include "modelstatus.h" #include #include #include #include using std::vector; using std::list; EllipsoidTool::EllipsoidTool() : m_smoothness( 2 ), m_isSphere( false ), m_fromCenter( false ) { } EllipsoidTool::~EllipsoidTool() { } void EllipsoidTool::activated( int arg, Model * model, QMainWindow * mainwin ) { log_debug( "ellipse activated\n" ); m_widget = new EllipsoidToolWidget( this, mainwin ); m_widget->show(); } void EllipsoidTool::deactivated() { m_widget->close(); } void EllipsoidTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); model->unselectAll(); // create rough 12-vertex sphere // Make top and bottom vertices ToolCoordT v1 = addPosition( parent, Model::PT_Vertex, NULL, 0, 1, 0 ); ToolCoordT v2 = addPosition( parent, Model::PT_Vertex, NULL, 0, -1, 0 ); // Make center vertices double offset = sin( 30 * PIOVER180 ); double adjust = cos( 30 * PIOVER180 ); vector top; vector bot; ToolCoordT v; double xoff; double zoff; for ( int t = 0; t < 5; t++ ) { // upper vertex xoff = sin ( ( t * 72) * PIOVER180 ) * adjust; zoff = cos ( ( t * 72) * PIOVER180 ) * adjust; v = addPosition( parent, Model::PT_Vertex, NULL, xoff, offset, zoff ); top.push_back( v.pos.index ); // lower vertex xoff = sin ( ( t * 72 + 36) * PIOVER180 ) * adjust; zoff = cos ( ( t * 72 + 36) * PIOVER180 ) * adjust; v = addPosition( parent, Model::PT_Vertex, NULL, xoff, -offset, zoff ); bot.push_back( v.pos.index ); } // Create top and bottom faces model->selectTriangle( model->addTriangle( v1.pos.index, top.back(), top.front() ) ); model->selectTriangle( model->addTriangle( v2.pos.index, bot.front(), bot.back() ) ); vector::iterator it1; vector::iterator it2; vector::reverse_iterator rit1; vector::reverse_iterator rit2; for ( it1 = top.begin(); ; it1++ ) { it2 = it1; it2++; if ( it2 == top.end() ) { break; } model->selectTriangle( model->addTriangle( v1.pos.index, *it1, *it2 ) ); } for ( rit1 = bot.rbegin(); ; rit1++ ) { rit2 = rit1; rit2++; if ( rit2 == bot.rend() ) { break; } model->selectTriangle( model->addTriangle( v2.pos.index, *rit1, *rit2 ) ); } model->selectTriangle( model->addTriangle( top[0], bot[0], top[1] ) ); model->selectTriangle( model->addTriangle( top[1], bot[1], top[2] ) ); model->selectTriangle( model->addTriangle( top[2], bot[2], top[3] ) ); model->selectTriangle( model->addTriangle( top[3], bot[3], top[4] ) ); model->selectTriangle( model->addTriangle( top[4], bot[4], top[0] ) ); model->selectTriangle( model->addTriangle( bot[1], top[1], bot[0] ) ); model->selectTriangle( model->addTriangle( bot[2], top[2], bot[1] ) ); model->selectTriangle( model->addTriangle( bot[3], top[3], bot[2] ) ); model->selectTriangle( model->addTriangle( bot[4], top[4], bot[3] ) ); model->selectTriangle( model->addTriangle( bot[0], top[0], bot[4] ) ); // create smooth sphere for ( unsigned i = 0; i < m_smoothness; i++ ) { model->subdivideSelectedTriangles(); } list posList; model->getSelectedPositions( posList ); m_vertices.clear(); // TODO add makeSelectedToolCoordList? makeToolCoordList( parent, m_vertices, posList ); ToolCoordList::iterator vit; for ( vit = m_vertices.begin(); vit != m_vertices.end(); vit++ ) { normalize3( (*vit).oldCoords ); } double pos[3] = {0,0,0}; double rad[3] = {0,0,0}; parent->getParentXYValue( x, y, pos[0], pos[1], true ); m_startX = pos[0]; m_startY = pos[1]; updateVertexCoords( parent, pos[0], pos[1], pos[2], rad[0], rad[1], rad[2] ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Ellipsoid created" ).toUtf8() ); } void EllipsoidTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { m_vertices.clear(); } void EllipsoidTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { double pos[3] = {0,0,0}; double rad[3] = {0,0,0}; parent->getParentXYValue( x, y, pos[0], pos[1] ); if ( m_isSphere ) { double sphereRadius = 0; double a, b; a = fabs((m_startX - pos[0]) / 2); b = fabs((m_startY - pos[1]) / 2); sphereRadius = (a < b) ? a : b; rad[0] = rad[1] = rad[2] = sphereRadius; } else { rad[0] = fabs(m_startX - pos[0]) / 2; rad[1] = fabs(m_startY - pos[1]) / 2; rad[2] = ( rad[0] < rad[1] ) ? rad[0] : rad[1]; } if ( m_fromCenter ) { pos[0] = m_startX; pos[1] = m_startY; rad[0] *= 2.0; rad[1] *= 2.0; rad[2] *= 2.0; } else { pos[0] = (pos[0] + m_startX) / 2; pos[1] = (pos[1] + m_startY) / 2; } updateVertexCoords( parent, pos[0], pos[1], pos[2], rad[0], rad[1], rad[2] ); parent->updateAllViews(); } const char ** EllipsoidTool::getPixmap() { return (const char **) ellipsetool_xpm; } void EllipsoidTool::updateVertexCoords( Tool::Parent * parent, double x, double y, double z, double xrad, double yrad, double zrad ) { ToolCoordList::iterator it; // TODO it would probably be considerably faster to copy the matrix // logic into this function for ( it = m_vertices.begin(); it != m_vertices.end(); it++ ) { movePosition( parent, (*it).pos, (*it).oldCoords[0]*xrad + x, (*it).oldCoords[1]*yrad + y, (*it).oldCoords[2]*zrad + z ); } } void EllipsoidTool::setSmoothnessValue( int newValue ) { m_smoothness = newValue; } void EllipsoidTool::setSphere( bool o ) { m_isSphere = o; } void EllipsoidTool::setCenter( bool o ) { m_fromCenter = o; } const char * EllipsoidTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Ellipsoid" ); } mm3d-master/src/tools/ellipsetool.h000066400000000000000000000041351324021725400176450ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ELLIPSOIDTOOL_H #define __ELLIPSOIDTOOL_H #include "tool.h" #include "ellipsetoolwidget.h" #include class EllipsoidTool : public Tool, public EllipsoidToolWidget::Observer { public: EllipsoidTool(); virtual ~EllipsoidTool(); int getToolCount() { return 1; }; const char * getName( int arg ); void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // EllipsoidToolWidget::Observer void setSmoothnessValue( int newValue ); void setSphere( bool o ); void setCenter( bool o ); protected: void updateVertexCoords( Tool::Parent *, double x, double y, double z, double xrad, double yrad, double zrad ); EllipsoidToolWidget * m_widget; unsigned m_smoothness; bool m_isSphere; bool m_fromCenter; ToolCoordList m_vertices; double m_startX; double m_startY; }; #endif // __ELLIPSOIDTOOL_H mm3d-master/src/tools/ellipsetoolwidget.cc000066400000000000000000000101271324021725400212050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "ellipsetoolwidget.h" #include #include #include #include #include #include #include #include #include "3dmprefs.h" EllipsoidToolWidget::EllipsoidToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_SMOOTHNESS = 2; const bool DEFAULT_SPHERE = false; const bool DEFAULT_CENTER = false; m_layout = boxLayout(); m_smoothLabel = new QLabel( tr("Smoothness:"), mainWidget() ); m_layout->addWidget( m_smoothLabel ); m_smoothValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_smoothValue ); m_smoothValue->setMinimum( 0 ); m_smoothValue->setMaximum( 5 ); m_facesLabel = new QLabel( tr("Faces: ") + QString("320"), mainWidget() ); m_layout->addWidget( m_facesLabel ); m_sphereCheckBox = new QCheckBox( tr("Sphere"), mainWidget() ); m_layout->addWidget( m_sphereCheckBox ); m_centerCheckBox = new QCheckBox( tr("From Center", "Checkbox that indicates if ellipsoid is created from center or far corner"), mainWidget() ); m_layout->addWidget( m_centerCheckBox ); int smoothVal = DEFAULT_SMOOTHNESS; g_prefs.setDefault( "ui_ellipsetool_smoothness", DEFAULT_SMOOTHNESS ); int val = g_prefs( "ui_ellipsetool_smoothness" ).intValue(); if ( val >= 0 && val <= 5 ) { smoothVal = val; } m_smoothValue->setValue( smoothVal ); g_prefs.setDefault( "ui_ellipsetool_issphere", DEFAULT_SPHERE ? 1 : 0 ); bool isSphere = DEFAULT_SPHERE; isSphere = (g_prefs( "ui_ellipsetool_issphere" ).intValue() != 0) ? true : false; m_sphereCheckBox->setChecked( isSphere ); g_prefs.setDefault( "ui_ellipsetool_fromcenter", DEFAULT_CENTER ? 1 : 0 ); bool fromCenter = DEFAULT_CENTER; fromCenter = (g_prefs( "ui_ellipsetool_fromcenter" ).intValue() != 0) ? true : false; m_centerCheckBox->setChecked( fromCenter ); m_layout->addStretch(); connect( m_smoothValue, SIGNAL(valueChanged(int)), this, SLOT(smoothnessValueChanged(int)) ); connect( m_sphereCheckBox, SIGNAL(toggled(bool)), this, SLOT(sphereCheckBoxValueChanged(bool)) ); connect( m_centerCheckBox, SIGNAL(toggled(bool)), this, SLOT(centerCheckBoxValueChanged(bool)) ); m_smoothLabel->show(); m_smoothValue->show(); m_facesLabel->show(); m_sphereCheckBox->show(); m_centerCheckBox->show(); smoothnessValueChanged( smoothVal ); sphereCheckBoxValueChanged( isSphere ); centerCheckBoxValueChanged( fromCenter ); } EllipsoidToolWidget::~EllipsoidToolWidget() { } void EllipsoidToolWidget::smoothnessValueChanged( int newValue ) { QString str = tr("Faces: "); str += QString::number( 20 * (unsigned) pow(4, newValue) ); m_facesLabel->setText( str ); g_prefs( "ui_ellipsetool_smoothness" ) = newValue; m_observer->setSmoothnessValue( newValue ); } void EllipsoidToolWidget::sphereCheckBoxValueChanged( bool o ) { g_prefs( "ui_ellipsetool_issphere" ) = o ? 1 : 0; m_observer->setSphere( o ); } void EllipsoidToolWidget::centerCheckBoxValueChanged( bool o ) { g_prefs( "ui_ellipsetool_fromcenter" ) = o ? 1 : 0; m_observer->setCenter( o ); } mm3d-master/src/tools/ellipsetoolwidget.h000066400000000000000000000037441324021725400210560ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ELLIPSETOOLWIDGET_H #define __ELLIPSETOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QLabel; class QCheckBox; #include "toolwidget.h" class EllipsoidToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setSmoothnessValue( int newValue ) = 0; virtual void setSphere( bool o ) = 0; virtual void setCenter( bool o ) = 0; }; EllipsoidToolWidget( Observer * observer, QMainWindow * parent ); virtual ~EllipsoidToolWidget(); public slots: void smoothnessValueChanged( int newValue ); void sphereCheckBoxValueChanged( bool o ); void centerCheckBoxValueChanged( bool o ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_smoothLabel; QSpinBox * m_smoothValue; QLabel * m_facesLabel; QCheckBox * m_sphereCheckBox; QCheckBox * m_centerCheckBox; }; #endif // __ELLIPSETOOLWIDGET_H mm3d-master/src/tools/extrudetool.cc000066400000000000000000000176531324021725400200370ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "extrudetool.h" #include "pixmap/extrudetool.xpm" #include "glmath.h" #include "model.h" #include "modelstatus.h" #include #include #include #include "log.h" ExtrudeTool::ExtrudeTool() { } ExtrudeTool::~ExtrudeTool() { } void ExtrudeTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_x = 0.0; m_y = 0.0; parent->getParentXYValue( x, y, m_x, m_y, true ); m_allowX = true; m_allowY = true; m_viewInverse = parent->getParentViewInverseMatrix(); m_model = parent->getModel(); extrudeEvent(); } void ExtrudeTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { /* Model * model = parent->getModel(); unsigned pcount = model->getProjectionCount(); for ( unsigned p = 0; p < pcount; p++ ) { if ( model->isProjectionSelected( p ) ) { model->applyProjection(p); } } */ parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Extrude complete" ).toUtf8() ); } void ExtrudeTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { Matrix m; double x2 = m_x; double y2 = m_y; parent->getParentXYValue( x, y, x2, y2 ); if ( buttonState & BS_Shift ) { if ( m_allowX && m_allowY ) { double ax = fabs( x2 - m_x ); double ay = fabs( y2 - m_y ); if ( ax > ay ) { m_allowY = false; } if ( ay > ax ) { m_allowX = false; } } } if ( !m_allowX ) { x2 = m_x; } if ( !m_allowY ) { y2 = m_y; } double v[4] = { x2 - m_x, y2 - m_y, 0.0, 1.0 }; m_x = x2; m_y = y2; m_viewInverse.apply3( v ); m.set( 3, 0, v[0] ); m.set( 3, 1, v[1] ); m.set( 3, 2, v[2] ); parent->getModel()->translateSelected( m ); parent->updateAllViews(); } const char ** ExtrudeTool::getPixmap() { return (const char **) extrudetool_xpm; } void ExtrudeTool::activated( int argc, Model * model, QMainWindow * mainwin ) { model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Tip: Hold shift to restrict movement to one dimension" ).toUtf8() ); } const char * ExtrudeTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Extrude" ); } // Extrude methods void ExtrudeTool::extrudeEvent() { m_sides.clear(); m_evMap.clear(); model_status( m_model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Extrude complete").toUtf8() ); list faces; m_model->getSelectedTriangles( faces ); list vertices; m_model->getSelectedVertices( vertices ); if ( faces.empty() ) { model_status( m_model, StatusError, STATUSTIME_LONG, qApp->translate( "Tool", "Must have faces selected to extrude" ).toUtf8() ); } else { // Find edges (sides with count==1) list::iterator it; for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); } for ( int t = 0; t < (3 - 1); t++ ) { addSide( v[t], v[t+1] ); } addSide( v[0], v[2] ); } // make extruded vertices and create a map from old vertices // to new vertices for ( it = vertices.begin(); it != vertices.end(); it++ ) { double coord[3]; m_model->getVertexCoords( *it, coord ); unsigned i = m_model->addVertex( coord[0], coord[1], coord[2] ); m_evMap[*it] = i; log_debug( "added vertex %d for %d at %f,%f,%f\n", m_evMap[*it], *it, coord[0], coord[1], coord[2] ); } // Add faces for edges for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned v[3]; for ( int t = 0; t < 3; t++ ) { v[t] = m_model->getTriangleVertex( *it, t ); } for ( int t = 0; t < (3 - 1); t++ ) { if ( sideIsEdge( v[t], v[t+1] ) ) { makeFaces( v[t], v[t+1] ); } } if ( sideIsEdge( v[2], v[0] ) ) { makeFaces( v[2], v[0] ); } } // Map selected faces onto extruded vertices for ( it = faces.begin(); it != faces.end(); it++ ) { unsigned tri = *it; int v1 = m_model->getTriangleVertex( tri, 0 ); int v2 = m_model->getTriangleVertex( tri, 1 ); int v3 = m_model->getTriangleVertex( tri, 2 ); /* // TODO widget for back-facing if ( m_backFaceCheckbox->isChecked() ) { int newTri = m_model->addTriangle( v1, v2, v3 ); m_model->invertNormals( newTri ); } */ log_debug( "face %d uses vertices %d,%d,%d\n", *it, v1, v2, v3 ); m_model->setTriangleVertices( tri, m_evMap[ m_model->getTriangleVertex( tri, 0 ) ], m_evMap[ m_model->getTriangleVertex( tri, 1 ) ], m_evMap[ m_model->getTriangleVertex( tri, 2 ) ] ); log_debug( "moved face %d to vertices %d,%d,%d\n", *it, m_model->getTriangleVertex( tri, 0 ), m_model->getTriangleVertex( tri, 1 ), m_model->getTriangleVertex( tri, 2 ) ); } // Update face selection ExtrudedVertexMap::iterator evit; for ( evit = m_evMap.begin(); evit != m_evMap.end(); evit++ ) { m_model->unselectVertex( (*evit).first ); m_model->selectVertex( (*evit).second ); } m_model->deleteOrphanedVertices(); model_status( m_model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Extruding selected faces" ).toUtf8() ); } } void ExtrudeTool::makeFaces( unsigned a, unsigned b ) { unsigned a2 = m_evMap[a]; unsigned b2 = m_evMap[b]; m_model->addTriangle( b, b2, a2 ); m_model->addTriangle( a2, a, b ); } void ExtrudeTool::addSide( unsigned a, unsigned b ) { // Make sure a < b to simplify comparison below if ( b < a ) { unsigned c = a; a = b; b = c; } // Find existing side (if any) and increment count SideList::iterator it; for ( it = m_sides.begin(); it != m_sides.end(); it++ ) { if ( (*it).a == a && (*it).b == b ) { (*it).count++; log_debug( "side (%d,%d) = %d\n", a, b, (*it).count ); return; } } // Not found, add new side with a count of 1 SideT s; s.a = a; s.b = b; s.count = 1; log_debug( "side (%d,%d) = %d\n", a, b, s.count ); m_sides.push_back( s ); } bool ExtrudeTool::sideIsEdge( unsigned a, unsigned b ) { // Make sure a < b to simplify comparison below if ( b < a ) { unsigned c = a; a = b; b = c; } SideList::iterator it; for ( it = m_sides.begin(); it != m_sides.end(); it++ ) { if ( (*it).a == a && (*it).b == b ) { if ( (*it).count == 1 ) { return true; } else { return false; } } } return false; } mm3d-master/src/tools/extrudetool.h000066400000000000000000000045011324021725400176650ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __EXTRUDETOOL_H #define __EXTRUDETOOL_H #include "tool.h" #include #include #include class ExtrudeTool: public Tool { public: ExtrudeTool(); virtual ~ExtrudeTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_M; return true; }; void activated( int argc, Model * model, QMainWindow * mainwin ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: // Extrude methods void extrudeEvent(); void makeFaces( unsigned a, unsigned b ); void addSide( unsigned a, unsigned b ); bool sideIsEdge( unsigned a, unsigned b ); // Extrude data struct _Side_t { unsigned a; unsigned b; int count; }; typedef struct _Side_t SideT; typedef std::list SideList; typedef std::map ExtrudedVertexMap; SideList m_sides; ExtrudedVertexMap m_evMap; // Tool data Model * m_model; Matrix m_viewInverse; double m_x; double m_y; bool m_allowX; bool m_allowY; }; #endif // __EXTRUDETOOL_H mm3d-master/src/tools/jointtool.cc000066400000000000000000000071751324021725400175000ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "jointtool.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "pixmap/jointtool.xpm" #include #include JointTool::JointTool() { m_joint.pos.type = Model::PT_Point; } JointTool::~JointTool() { } void JointTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1], true ); const Matrix & viewMatrix = parent->getParentViewMatrix(); int p = -1; double pDist = 0.0; double parentCoords[4]; int jointCount = model->getBoneJointCount(); for ( int t = 0; t < jointCount; t++ ) { model->getBoneJointCoords( t, parentCoords ); parentCoords[3] = 1; viewMatrix.apply( parentCoords ); double dist = distance( coord[0], coord[1], parentCoords[0], parentCoords[1] ); if ( p == -1 || dist < pDist ) { p = t; pDist = dist; } } // Find a unique name for the joint char name[32] = "Joint 1"; unsigned c = model->getBoneJointCount(); bool uniqueName = (c == 0) ? true : false; for ( unsigned i = 1; !uniqueName && i < 1000; i++ ) { uniqueName = true; sprintf( name, "Joint %d", i ); for ( unsigned j = 0; j < c; j++ ) { if ( strcmp( name, model->getBoneJointName( j ) ) == 0 ) { uniqueName = false; break; } } } // I give up, just call it "Joint" if ( ! uniqueName ) { strcpy( name, "Joint" ); } m_joint = addPosition( parent, Model::PT_Joint, name, coord[0], coord[1], coord[2], 0, 0, 0, p ); model->unselectAll(); model->selectBoneJoint( m_joint.pos.index ); parent->updateAllViews(); if ( p >= 0 ) { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Joint created" ).toUtf8() ); } else { model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Root joint created" ).toUtf8() ); } } void JointTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_joint.pos.type == Model::PT_Joint ) { double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1] ); movePosition( parent, m_joint.pos, coord[0], coord[1], coord[2] ); parent->updateAllViews(); } } void JointTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { } const char ** JointTool::getPixmap() { return (const char **) jointtool_xpm; } const char * JointTool::getPath() { return TOOLS_CREATE_MENU; } const char * JointTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Bone Joint" ); } mm3d-master/src/tools/jointtool.h000066400000000000000000000027421324021725400173350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __JOINTTOOL_H #define __JOINTTOOL_H #include "tool.h" class JointTool : public Tool { public: JointTool(); virtual ~JointTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: ToolCoordT m_joint; }; #endif // __JOINTTOOL_H mm3d-master/src/tools/movetool.cc000066400000000000000000000063331324021725400173160ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "movetool.h" #include "pixmap/movetool.xpm" #include "glmath.h" #include "model.h" #include "modelstatus.h" #include #include #include #include "log.h" MoveTool::MoveTool() { } MoveTool::~MoveTool() { } void MoveTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_x = 0.0; m_y = 0.0; parent->getParentXYValue( x, y, m_x, m_y, true ); m_allowX = true; m_allowY = true; m_viewInverse = parent->getParentViewInverseMatrix(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Moving selected primitives" ).toUtf8() ); } void MoveTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { /* Model * model = parent->getModel(); unsigned pcount = model->getProjectionCount(); for ( unsigned p = 0; p < pcount; p++ ) { if ( model->isProjectionSelected( p ) ) { model->applyProjection(p); } } */ parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Move complete" ).toUtf8() ); } void MoveTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { Matrix m; double x2 = m_x; double y2 = m_y; parent->getParentXYValue( x, y, x2, y2 ); if ( buttonState & BS_Shift ) { if ( m_allowX && m_allowY ) { double ax = fabs( x2 - m_x ); double ay = fabs( y2 - m_y ); if ( ax > ay ) { m_allowY = false; } if ( ay > ax ) { m_allowX = false; } } } if ( !m_allowX ) { x2 = m_x; } if ( !m_allowY ) { y2 = m_y; } double v[4] = { x2 - m_x, y2 - m_y, 0.0, 1.0 }; m_x = x2; m_y = y2; m_viewInverse.apply3( v ); m.set( 3, 0, v[0] ); m.set( 3, 1, v[1] ); m.set( 3, 2, v[2] ); parent->getModel()->translateSelected( m ); parent->updateAllViews(); } const char ** MoveTool::getPixmap() { return (const char **) movetool_xpm; } void MoveTool::activated( int argc, Model * model, QMainWindow * mainwin ) { model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Tip: Hold shift to restrict movement to one dimension" ).toUtf8() ); } const char * MoveTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Move" ); } mm3d-master/src/tools/movetool.h000066400000000000000000000033341324021725400171560ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __MOVETOOL_H #define __MOVETOOL_H #include "tool.h" #include class MoveTool: public Tool { public: MoveTool(); virtual ~MoveTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_M; return true; }; void activated( int argc, Model * model, QMainWindow * mainwin ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: Matrix m_viewInverse; double m_x; double m_y; bool m_allowX; bool m_allowY; }; #endif // __MOVETOOL_H mm3d-master/src/tools/pointtool.cc000066400000000000000000000056631324021725400175060ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "pointtool.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "pixmap/pointtool.xpm" #include #include PointTool::PointTool() { m_point.pos.type = Model::PT_Vertex; } PointTool::~PointTool() { } void PointTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1], true ); // Find a unique name for the point char name[32] = "Point 1"; unsigned c = model->getPointCount(); bool uniqueName = (c == 0) ? true : false; for ( unsigned i = 1; !uniqueName && i < 1000; i++ ) { uniqueName = true; sprintf( name, "Point %d", i ); for ( unsigned j = 0; j < c; j++ ) { if ( strcmp( name, model->getPointName( j ) ) == 0 ) { uniqueName = false; break; } } } // I give up, just call it "Point" if ( ! uniqueName ) { strcpy( name, "Point" ); } m_point = addPosition( parent, Model::PT_Point, name, coord[0], coord[1], coord[2], 0, 0, 0 ); model->unselectAll(); model->selectPoint( m_point.pos.index ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Point created" ).toUtf8() ); } void PointTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_point.pos.type == Model::PT_Point ) { double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1] ); movePosition( parent, m_point.pos, coord[0], coord[1], coord[2] ); parent->updateAllViews(); } } void PointTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { } const char ** PointTool::getPixmap() { return (const char **) pointtool_xpm; } const char * PointTool::getPath() { return TOOLS_CREATE_MENU; } const char * PointTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Point" ); } mm3d-master/src/tools/pointtool.h000066400000000000000000000027421324021725400173430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POINTTOOL_H #define __POINTTOOL_H #include "tool.h" class PointTool : public Tool { public: PointTool(); virtual ~PointTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: ToolCoordT m_point; }; #endif // __POINTTOOL_H mm3d-master/src/tools/polytool.cc000066400000000000000000000122531324021725400173310ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "polytool.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "pixmap/polytool.xpm" #include #include PolyTool::PolyTool() : m_model( NULL ), m_type( 0 ), m_widget( NULL ) { m_lastVertex.pos.type = Model::PT_Point; m_lastVertex.pos.index = 0; } PolyTool::~PolyTool() { } void PolyTool::activated( int arg, Model * model, QMainWindow * mainwin ) { m_model = model; m_widget = new PolyToolWidget( this, mainwin ); m_widget->show(); } void PolyTool::deactivated() { m_model->deleteOrphanedVertices(); m_widget->close(); } void PolyTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); m_model = model; if ( buttonState == BS_Left ) { m_verts.clear(); IntList selected; model->getSelectedVertices( selected ); IntList::iterator it; for ( it = selected.begin(); m_verts.size() < 3 && it != selected.end(); it++ ) { m_verts.push_back( *it ); } double coord[3] = {0,0,0}; // Technically that last argument could be true, I chose false // because for the poly tool you'd end up creating a flat triangle // that would just get deleted parent->getParentXYValue( x, y, coord[0], coord[1], false ); m_lastVertex = addPosition( parent, Model::PT_Vertex, NULL, coord[0], coord[1], coord[2] ); if ( m_verts.size() == 3 ) { if ( m_type == 0 ) { // Fan int v = m_verts.front(); model->unselectVertex( v ); m_verts.pop_front(); m_verts.push_back( m_lastVertex.pos.index ); } else { // Strip it = m_verts.begin(); it++; int v = *it; m_verts.erase( it ); model->unselectVertex( v ); m_verts.push_back( m_lastVertex.pos.index ); } } else { m_verts.push_back( m_lastVertex.pos.index ); } if ( m_verts.size() == 3 ) { it = m_verts.begin(); int v1 = *it; it++; int v2 = *it; it++; int v3 = *it; it++; int t = model->addTriangle( v1, v2, v3 ); model->beginSelectionDifference(); //model->unselectAllTriangles(); model->selectVertex( m_lastVertex.pos.index ); //model->selectTriangle( t ); const Matrix & viewMatrix = parent->getParentViewInverseMatrix(); Vector viewNorm( 0, 0, 1 ); viewMatrix.show(); viewNorm.transform3( viewMatrix ); float norm[4] = { 1.0f, 0.0f, 0.0f, 0.0f }; model->calculateNormals(); model->getNormal( t, 0, norm ); Vector triNorm( norm[0], norm[1], norm[2] ); log_debug( "view normal is %f %f %f\n", (float) viewNorm[0], (float) viewNorm[1], (float) viewNorm[2] ); log_debug( "triangle normal is %f %f %f\n", (float) triNorm[0], (float) triNorm[1], (float) triNorm[2] ); double d = viewNorm.dot3( triNorm ); log_debug( "dot product is %f\n", (float) d ); if( d < 0 ) { model->invertNormals( t ); } } else { model->beginSelectionDifference(); model->selectVertex( m_lastVertex.pos.index ); } model->endSelectionDifference(); parent->updateAllViews(); } } void PolyTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( buttonState == BS_Left ) { if ( m_lastVertex.pos.type == Model::PT_Vertex ) { double coord[3] = {0,0,0}; // I chose false for the same reason as above parent->getParentXYValue( x, y, coord[0], coord[1], false ); movePosition( parent, m_lastVertex.pos, coord[0], coord[1], coord[2] ); parent->updateAllViews(); } } } void PolyTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { } const char ** PolyTool::getPixmap() { return (const char **) polytool_xpm; } void PolyTool::setTypeValue( int newValue ) { m_type = newValue; } const char * PolyTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Polygon" ); } mm3d-master/src/tools/polytool.h000066400000000000000000000034771324021725400172030ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POLYTOOL_H #define __POLYTOOL_H #include "tool.h" #include "polytoolwidget.h" #include typedef std::list IntList; class PolyTool : public Tool, public PolyToolWidget::Observer { public: PolyTool(); virtual ~PolyTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool isCreation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // Observer methods void setTypeValue( int newValue ); protected: Model * m_model; ToolCoordT m_lastVertex; IntList m_verts; int m_type; PolyToolWidget * m_widget; }; #endif // __POLYTOOL_H mm3d-master/src/tools/polytoolwidget.cc000066400000000000000000000042411324021725400205330ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "polytoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include #include PolyToolWidget::PolyToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_FAN = 0; m_layout = boxLayout(); m_typeLabel = new QLabel( tr("Poly Type"), mainWidget() ); m_layout->addWidget( m_typeLabel ); m_typeValue = new QComboBox( mainWidget() ); m_typeValue->insertItem( 0, tr("Strip", "Triangle strip option") ); m_typeValue->insertItem( 1, tr("Fan", "Triangle fan option") ); m_layout->addWidget( m_typeValue ); g_prefs.setDefault( "ui_polytool_is_fan", DEFAULT_FAN ); int index = g_prefs( "ui_polytool_isfan" ).intValue(); m_typeValue->setCurrentIndex( (index == 0) ? 0 : 1 ); m_layout->addStretch(); connect( m_typeValue, SIGNAL(activated(int)), this, SLOT(typeValueChanged(int)) ); m_typeLabel->show(); m_typeValue->show(); typeValueChanged( index ); } PolyToolWidget::~PolyToolWidget() { } void PolyToolWidget::typeValueChanged( int newValue ) { g_prefs( "ui_polytool_isfan" ) = newValue; m_observer->setTypeValue( newValue ); } mm3d-master/src/tools/polytoolwidget.h000066400000000000000000000033261324021725400204000ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __POLYTOOLWIDGET_H #define __POLYTOOLWIDGET_H class QMainWindow; class QLabel; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QComboBox; class QLabel; #include "toolwidget.h" class PolyToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setTypeValue( int type ) = 0; }; PolyToolWidget( Observer * observer, QMainWindow * parent ); virtual ~PolyToolWidget(); public slots: void typeValueChanged( int type ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_typeLabel; QComboBox * m_typeValue; QLabel * m_segmentLabel; QSpinBox * m_segmentValue; }; #endif // __POLYTOOLWIDGET_H mm3d-master/src/tools/projtool.cc000066400000000000000000000125201324021725400173150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "projtool.h" #include "projtoolwidget.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "pixmap/projtool.xpm" #include #include ProjectionTool::ProjectionTool() : m_type( Model::TPT_Sphere ) { m_proj.pos.type = Model::PT_Vertex; } ProjectionTool::~ProjectionTool() { } void ProjectionTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_allowX = true; m_allowY = true; m_x = x; m_y = y; Model * model = parent->getModel(); model->setDrawProjections( true ); // use parent view matrix to translate 2D coords into 3D coords double coord[4] = {0,0,0,1}; parent->getParentXYValue( x, y, coord[0], coord[1], true ); Matrix m = parent->getParentViewInverseMatrix(); m.apply( coord ); // Find a unique name for the projection char name[32] = "Projection 1"; unsigned c = model->getProjectionCount(); bool uniqueName = (c == 0) ? true : false; for ( unsigned i = 1; !uniqueName && i < 1000; i++ ) { uniqueName = true; sprintf( name, "Projection %d", i ); for ( unsigned j = 0; j < c; j++ ) { if ( strcmp( name, model->getProjectionName( j ) ) == 0 ) { uniqueName = false; break; } } } // I give up, just call it "Projection" if ( ! uniqueName ) { strcpy( name, "Projection" ); } m_orig[0] = coord[0]; m_orig[1] = coord[1]; m_orig[2] = coord[2]; // Create projection m_proj.pos.type = Model::PT_Projection; m_proj.pos.index = model->addProjection( name, static_cast( m_type ), coord[0], coord[1], coord[2] ); double upVec[3] = { 0, 1, 0 }; double seamVec[3] = { 0, 0, -1.0 / 3.0 }; m.apply3( upVec ); m.apply3( seamVec ); model->setProjectionUp( m_proj.pos.index, upVec ); model->setProjectionSeam( m_proj.pos.index, seamVec ); model->setProjectionScale( m_proj.pos.index, 1.0 ); // Assign selected faces to projection unsigned tcount = model->getTriangleCount(); for ( unsigned t = 0; t < tcount; t++ ) { if ( model->isTriangleSelected( t ) ) { model->setTriangleProjection( t, m_proj.pos.index ); } } model->applyProjection( m_proj.pos.index ); // Make new projection the only thing selected model->unselectAll(); model->selectProjection( m_proj.pos.index ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Projection created" ).toUtf8() ); } void ProjectionTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_proj.pos.type == Model::PT_Projection ) { if ( buttonState & BS_Shift ) { if ( m_allowX && m_allowY ) { double ax = fabs( x - m_x ); double ay = fabs( y - m_y ); if ( ax > ay ) { m_allowY = false; } if ( ay > ax ) { m_allowX = false; } } } if ( !m_allowX ) { x = m_x; } if ( !m_allowY ) { y = m_y; } double coord[3] = {0,0,0}; // Convert 2D coords to 3D in parent's view space parent->getParentXYValue( x, y, coord[0], coord[1] ); Matrix m = parent->getParentViewInverseMatrix(); double tranVec[4] = { coord[0], coord[1], 0.0, 1.0 }; m.apply( tranVec ); tranVec[0] -= m_orig[0]; tranVec[1] -= m_orig[1]; tranVec[2] -= m_orig[2]; // Set the up vector to whereever the mouse is Model * model = parent->getModel(); model->setProjectionUp( m_proj.pos.index, tranVec ); //model->applyProjection( m_proj.pos.index ); parent->updateAllViews(); } } void ProjectionTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { } const char ** ProjectionTool::getPixmap() { return (const char **) projtool_xpm; } const char * ProjectionTool::getPath() { return TOOLS_CREATE_MENU; } const char * ProjectionTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Projection" ); } void ProjectionTool::setTypeValue( int newValue ) { m_type = newValue; } void ProjectionTool::activated( int arg, Model * model, QMainWindow * mainwin ) { m_widget = new ProjToolWidget( this, mainwin ); m_widget->show(); } void ProjectionTool::deactivated() { m_widget->close(); } mm3d-master/src/tools/projtool.h000066400000000000000000000035601324021725400171630ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PROJTOOL_H #define __PROJTOOL_H #include "tool.h" #include "projtoolwidget.h" class ProjectionTool : public Tool, public ProjToolWidget::Observer { public: ProjectionTool(); virtual ~ProjectionTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool isCreation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // Observer methods void setTypeValue( int newValue ); protected: ToolCoordT m_proj; double m_orig[3]; int m_x; int m_y; bool m_allowX; bool m_allowY; int m_type; ProjToolWidget * m_widget; }; #endif // __PROJTOOL_H mm3d-master/src/tools/projtoolwidget.cc000066400000000000000000000046611324021725400205300ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "projtoolwidget.h" #include "3dmprefs.h" #include "model.h" #include #include #include #include #include #include ProjToolWidget::ProjToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_TYPE = Model::TPT_Sphere; m_layout = boxLayout(); m_typeLabel = new QLabel( tr("Type"), mainWidget() ); m_layout->addWidget( m_typeLabel ); m_typeValue = new QComboBox( mainWidget() ); m_layout->addWidget( m_typeValue ); m_typeValue->insertItem( Model::TPT_Cylinder, tr("Cylinder", "Cylinder projection type") ); m_typeValue->insertItem( Model::TPT_Sphere, tr("Sphere", "Sphere projection type") ); m_typeValue->insertItem( Model::TPT_Plane, tr("Plane", "Plane projection type") ); int typeIndex = DEFAULT_TYPE; g_prefs.setDefault( "ui_projtool_type_index", DEFAULT_TYPE ); int temp = g_prefs( "ui_projtool_type_index" ).intValue(); if ( temp >= Model::TPT_Cylinder && temp <= Model::TPT_Plane ) { typeIndex = temp; } m_typeValue->setCurrentIndex( typeIndex ); m_layout->addStretch(); connect( m_typeValue, SIGNAL(activated(int)), this, SLOT(typeValueChanged(int)) ); m_typeLabel->show(); m_typeValue->show(); typeValueChanged( typeIndex ); } ProjToolWidget::~ProjToolWidget() { } void ProjToolWidget::typeValueChanged( int newValue ) { g_prefs( "ui_projtool_type_index" ) = newValue; m_observer->setTypeValue( newValue ); } mm3d-master/src/tools/projtoolwidget.h000066400000000000000000000031301324021725400203600ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __PROJTOOLWIDGET_H #define __PROJTOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QComboBox; class QLabel; #include "toolwidget.h" class ProjToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setTypeValue( int newValue ) = 0; }; ProjToolWidget( Observer * observer, QMainWindow * parent ); virtual ~ProjToolWidget(); public slots: void typeValueChanged( int newValue ); protected: Observer * m_observer; QBoxLayout * m_layout; QLabel * m_typeLabel; QComboBox * m_typeValue; }; #endif // __PROJTOOLWIDGET_H mm3d-master/src/tools/rectangletool.cc000066400000000000000000000066301324021725400203140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "rectangletool.h" #include "pixmap/rectangletool.xpm" #include "log.h" #include "model.h" #include "modelstatus.h" #include #include RectangleTool::RectangleTool() : m_tracking( false ), m_parent( NULL ) { } RectangleTool::~RectangleTool() { } void RectangleTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( !m_tracking ) { m_parent = parent; // Keep track of which parent we're serving m_tracking = true; m_x1 = 0.0; m_y1 = 0.0; parent->getParentXYValue( x, y, m_x1, m_y1 ); Model * model = parent->getModel(); model->unselectAll(); log_debug( "model has %d vertices\n", model->getVertexCount() ); m_v1 = addPosition( parent, Model::PT_Vertex, NULL, m_x1, m_y1, 0.0 ); m_v2 = addPosition( parent, Model::PT_Vertex, NULL, m_x1, m_y1, 0.0 ); m_v3 = addPosition( parent, Model::PT_Vertex, NULL, m_x1, m_y1, 0.0 ); m_v4 = addPosition( parent, Model::PT_Vertex, NULL, m_x1, m_y1, 0.0 ); log_debug( "last new vertex: %d\n", m_v4.pos.index ); model->addTriangle( m_v1.pos.index, m_v2.pos.index, m_v4.pos.index ); model->addTriangle( m_v4.pos.index, m_v3.pos.index, m_v1.pos.index ); model->selectVertex( m_v1.pos.index ); model->selectVertex( m_v2.pos.index ); model->selectVertex( m_v3.pos.index ); model->selectVertex( m_v4.pos.index ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Rectangle created" ).toUtf8() ); } } void RectangleTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { m_tracking = false; } void RectangleTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( parent != m_parent ) { log_error( "Can't serve two parents at once\n" ); } if ( m_tracking ) { double x2 = 0.0; double y2 = 0.0; parent->getParentXYValue( x, y, x2, y2 ); movePosition( parent, m_v2.pos, m_x1, y2, 0.0 ); movePosition( parent, m_v3.pos, x2, m_y1, 0.0 ); movePosition( parent, m_v4.pos, x2, y2, 0.0 ); parent->updateAllViews(); } } const char ** RectangleTool::getPixmap() { return (const char **) rectangletool_xpm; } const char * RectangleTool::getPath() { return TOOLS_CREATE_MENU; } const char * RectangleTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Rectangle" ); } mm3d-master/src/tools/rectangletool.h000066400000000000000000000032231324021725400201510ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __RECTANGLETOOL_H #define __RECTANGLETOOL_H #include "tool.h" class RectangleTool : public Tool { public: RectangleTool(); virtual ~RectangleTool(); int getToolCount() { return 1; }; const char * getPath(); const char * getName( int arg ); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: bool m_tracking; Parent * m_parent; ToolCoordT m_v1; ToolCoordT m_v2; ToolCoordT m_v3; ToolCoordT m_v4; double m_x1; double m_y1; }; #endif // __RECTANGLETOOL_H mm3d-master/src/tools/rotatetool.cc000066400000000000000000000224001324021725400176370ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "rotatetool.h" #include "model.h" #include "pixmap/rotatetool.xpm" #include "glmath.h" #include "decalmgr.h" #include "rotatepoint.h" #include "log.h" #include "modelstatus.h" #include #include #include static void _add_coords( double * dest, double * rhs, double * lhs ) { dest[0] = rhs[0] + lhs[0]; dest[1] = rhs[1] + lhs[1]; dest[2] = rhs[2] + lhs[2]; } RotateTool::RotateTool() : m_model( NULL ), m_tracking( false ), m_widget( NULL ) { } RotateTool::~RotateTool() { } void RotateTool::setModel( Model * model ) { m_model = model; } void RotateTool::activated( int arg, Model * model, QMainWindow * mainwin ) { m_model = model; model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Tip: Hold shift to rotate in 15 degree increments" ).toUtf8() ); m_coords[0] = 0; m_coords[1] = 0; m_coords[2] = 0; m_coords[3] = 1; if ( model->getAnimationMode() == Model::ANIMMODE_SKELETAL ) { list joints; model->getSelectedBoneJoints( joints ); if ( joints.size() > 0 ) { model->getBoneJointCoords( joints.front(), m_coords ); } } else { double coords[3]; unsigned count = 0; unsigned vcount = model->getVertexCount(); for ( unsigned int v = 0; v < vcount; v++ ) { if ( model->isVertexSelected( v ) ) { model->getVertexCoords( v, coords ); _add_coords( m_coords, m_coords, coords ); count++; } } unsigned int bcount = model->getBoneJointCount(); for ( unsigned int b = 0; b < bcount; b++ ) { if ( model->isBoneJointSelected( b ) ) { model->getBoneJointCoords( b, coords ); _add_coords( m_coords, m_coords, coords ); count++; } } unsigned int pcount = model->getPointCount(); for ( unsigned int p = 0; p < pcount; p++ ) { if ( model->isPointSelected( p ) ) { model->getPointTranslation( p, coords ); _add_coords( m_coords, m_coords, coords ); count++; } } unsigned int rcount = model->getProjectionCount(); for ( unsigned int r = 0; r < rcount; r++ ) { if ( model->isProjectionSelected( r ) ) { model->getProjectionCoords( r, coords ); _add_coords( m_coords, m_coords, coords ); count++; } } m_coords[0] = m_coords[0] / (double) count; m_coords[1] = m_coords[1] / (double) count; m_coords[2] = m_coords[2] / (double) count; } m_rotatePoint = new RotatePoint(); m_rotatePoint->setPoint( m_coords[0], m_coords[1], m_coords[2] ); DecalManager::getInstance()->addDecalToModel( m_rotatePoint, model ); m_widget = new RotateToolWidget( this, mainwin, m_coords[0], m_coords[1], m_coords[2] ); m_widget->show(); } void RotateTool::deactivated() { DecalManager::getInstance()->removeDecal( m_rotatePoint ); delete m_rotatePoint; m_rotatePoint = NULL; m_widget->close(); m_widget = NULL; } void RotateTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); m_model = model; if ( model->getAnimationMode() == Model::ANIMMODE_SKELETAL ) { list joints; model->getSelectedBoneJoints( joints ); if ( joints.size() > 0 ) { model->getBoneJointCoords( joints.front(), m_coords ); m_widget->setCoords( m_coords[0], m_coords[1], m_coords[2] ); m_rotatePoint->setPoint( m_coords[0], m_coords[1], m_coords[2] ); } } double newCoords[3] = {0,0,0}; parent->getParentXYValue( x, y, newCoords[0], newCoords[1], true ); m_viewMatrix = parent->getParentViewMatrix(); m_viewInverse = parent->getParentViewInverseMatrix(); if ( buttonState & BS_Left ) { m_tracking = true; getRotateCoords( parent ); double xDiff = newCoords[0] - m_coords[0]; double yDiff = newCoords[1] - m_coords[1]; double angle = diffToAngle( yDiff, xDiff ); if ( buttonState & BS_Shift ) { angle = adjustToNearest( angle ); } m_startAngle = angle; model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Rotating selected primitives" ).toUtf8() ); } else if ( buttonState & BS_Right && model->getAnimationMode() != Model::ANIMMODE_SKELETAL ) { for ( int t = 0; t < 3; t++ ) { m_coords[t] = newCoords[t]; } m_coords[3] = 1; m_viewInverse.apply( m_coords ); m_widget->setCoords( m_coords[0], m_coords[1], m_coords[2] ); m_rotatePoint->setPoint( m_coords[0], m_coords[1], m_coords[2] ); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Setting rotation point" ).toUtf8() ); } parent->updateAllViews(); } void RotateTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); m_model = model; double newCoords[3] = {0,0,0}; parent->getParentXYValue( x, y, newCoords[0], newCoords[1] ); if ( buttonState & BS_Left ) { getRotateCoords( parent ); double xDiff = newCoords[0] - m_coords[0]; double yDiff = newCoords[1] - m_coords[1]; double angles[3] = { 0, 0, 0 }; Matrix m; double angle = diffToAngle( yDiff, xDiff ); if ( buttonState & BS_Shift ) { angle = adjustToNearest( angle ); } angles[2] = (angle - m_startAngle); double vec[4] = { 0, 0, 1, 1 }; m_viewInverse.apply3( vec ); m.setRotationOnAxis( vec, angle - m_startAngle ); m_coords[3] = 1; m_viewInverse.apply( m_coords ); model->rotateSelected( m, m_coords ); m_startAngle = angle; } else if ( buttonState & BS_Right ) { getRotateCoords( parent ); for ( int t = 0; t < 3; t++ ) { m_coords[t] = newCoords[t]; } m_coords[3] = 1; m_viewInverse.apply( m_coords ); m_widget->setCoords( m_coords[0], m_coords[1], m_coords[2] ); m_rotatePoint->setPoint( m_coords[0], m_coords[1], m_coords[2] ); } parent->updateAllViews(); } void RotateTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { parent->updateAllViews(); m_tracking = false; if ( buttonState & BS_Left ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Rotate complete" ).toUtf8() ); } } const char ** RotateTool::getPixmap() { return (const char **) rotatetool_xpm; } double RotateTool::diffToAngle( double opposite, double adjacent ) { if ( adjacent < 0.0001 && adjacent > -0.0001 ) { adjacent = (adjacent >= 0 ) ? 0.0001 : -0.0001; } double angle = atan( opposite / adjacent ); float quad = PIOVER180 * 90; if ( adjacent < 0 ) { if ( opposite < 0 ) { angle = -(quad) - ( (quad) - angle ); } else { angle = (quad) + ( (quad) + angle ); } } return angle; } void RotateTool::getRotateCoords( Tool::Parent * parent ) { m_rotatePoint->getPoint( m_coords[0], m_coords[1], m_coords[2] ); m_coords[3] = 1; m_viewMatrix.apply( m_coords ); } double RotateTool::adjustToNearest( double angle ) { double f = angle / PIOVER180; // Change to degrees if ( f < 0.0 ) { int n = (int) (f / 15.0 - 0.5); f = n * 15.0; } else { int n = (int) (f / 15.0 + 0.5); f = n * 15.0; } log_debug( "nearest angle is %f\n", f ); return f * PIOVER180; } const char * RotateTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Rotate" ); } void RotateTool::setXValue( double newValue ) { double x = 0; double y = 0; double z = 0; m_rotatePoint->getPoint( x, y, z ); x = newValue; m_rotatePoint->setPoint( x, y, z ); DecalManager::getInstance()->modelUpdated( m_model ); } void RotateTool::setYValue( double newValue ) { double x = 0; double y = 0; double z = 0; m_rotatePoint->getPoint( x, y, z ); y = newValue; m_rotatePoint->setPoint( x, y, z ); DecalManager::getInstance()->modelUpdated( m_model ); } void RotateTool::setZValue( double newValue ) { double x = 0; double y = 0; double z = 0; m_rotatePoint->getPoint( x, y, z ); z = newValue; m_rotatePoint->setPoint( x, y, z ); DecalManager::getInstance()->modelUpdated( m_model ); } mm3d-master/src/tools/rotatetool.h000066400000000000000000000046121324021725400175060ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __ROTATETOOL_H #define __ROTATETOOL_H #include "tool.h" #include #include #include "rotatetoolwidget.h" class Model; class RotatePoint; class RotateTool : public Tool, public RotateToolWidget::Observer { public: RotateTool(); virtual ~RotateTool(); int getToolCount() { return 1; }; const char * getName( int arg ); void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void setModel( Model * model ); bool getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_R; return true; }; bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // RotateToolWidget::Observer void setXValue( double newValue ); void setYValue( double newValue ); void setZValue( double newValue ); protected: Model * m_model; Matrix m_viewMatrix; Matrix m_viewInverse; double diffToAngle( double opposite, double adjacent ); double adjustToNearest( double angle ); void getRotateCoords( Tool::Parent * ); double m_startAngle; double m_originX; double m_originY; double m_coords[4]; bool m_tracking; RotatePoint * m_rotatePoint; RotateToolWidget * m_widget; }; #endif // __ROTATETOOL_H mm3d-master/src/tools/rotatetoolwidget.cc000066400000000000000000000066441324021725400210570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "rotatetoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include RotateToolWidget::RotateToolWidget( Observer * observer, QMainWindow * parent, double x, double y, double z ) : ToolWidget ( parent ), m_observer( observer ), m_ignore( false ) { m_layout = boxLayout(); m_xLabel = new QLabel( tr("X"), mainWidget() ); m_layout->addWidget( m_xLabel ); m_xValue = new QLineEdit( mainWidget() ); m_xValue->setMinimumWidth( 100 ); m_layout->addWidget( m_xValue ); m_xValue->setText( QString::number( x, 'f' ) ); m_yLabel = new QLabel( tr("Y"), mainWidget() ); m_layout->addWidget( m_yLabel ); m_yValue = new QLineEdit( mainWidget() ); m_yValue->setMinimumWidth( 100 ); m_layout->addWidget( m_yValue ); m_yValue->setText( QString::number( y, 'f' ) ); m_zLabel = new QLabel( tr("Z"), mainWidget() ); m_layout->addWidget( m_zLabel ); m_zValue = new QLineEdit( mainWidget() ); m_zValue->setMinimumWidth( 100 ); m_layout->addWidget( m_zValue ); m_zValue->setText( QString::number( z, 'f' ) ); m_layout->addStretch(); connect( m_xValue, SIGNAL(textChanged(const QString &)), this, SLOT(xValueChanged(const QString &)) ); connect( m_yValue, SIGNAL(textChanged(const QString &)), this, SLOT(yValueChanged(const QString &)) ); connect( m_zValue, SIGNAL(textChanged(const QString &)), this, SLOT(zValueChanged(const QString &)) ); m_xLabel->show(); m_xValue->show(); m_yLabel->show(); m_yValue->show(); m_zLabel->show(); m_zValue->show(); // Unlike other tool widgets, our initial settings came from the tool, // so we don't call the slots directly to update the tool's settings. } RotateToolWidget::~RotateToolWidget() { } void RotateToolWidget::xValueChanged( const QString & newValue ) { if ( m_ignore ) return; m_observer->setXValue( newValue.toDouble() ); } void RotateToolWidget::yValueChanged( const QString & newValue ) { if ( m_ignore ) return; m_observer->setYValue( newValue.toDouble() ); } void RotateToolWidget::zValueChanged( const QString & newValue ) { if ( m_ignore ) return; m_observer->setZValue( newValue.toDouble() ); } void RotateToolWidget::setCoords( double x, double y, double z ) { m_ignore = true; m_xValue->setText( QString::number( x, 'f' ) ); m_yValue->setText( QString::number( y, 'f' ) ); m_zValue->setText( QString::number( z, 'f' ) ); m_ignore = false; } mm3d-master/src/tools/rotatetoolwidget.h000066400000000000000000000041551324021725400207140ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef ROTATETOOLWIDGET_H_INC__ #define ROTATETOOLWIDGET_H_INC__ class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QLineEdit; class QLabel; #include "toolwidget.h" class RotateToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setXValue( double newValue ) = 0; virtual void setYValue( double newValue ) = 0; virtual void setZValue( double newValue ) = 0; }; RotateToolWidget( Observer * observer, QMainWindow * parent, double x, double y, double z ); virtual ~RotateToolWidget(); void setCoords( double x, double y, double z ); public slots: void xValueChanged( const QString & newValue ); void yValueChanged( const QString & newValue ); void zValueChanged( const QString & newValue ); protected: Observer * m_observer; bool m_ignore; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_xLabel; QLineEdit * m_xValue; QLabel * m_yLabel; QLineEdit * m_yValue; QLabel * m_zLabel; QLineEdit * m_zValue; }; #endif // ROTATETOOLWIDGET_H_INC__ mm3d-master/src/tools/scaletool.cc000066400000000000000000000223421324021725400174350ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "scaletool.h" #include "model.h" #include "log.h" #include "modelstatus.h" #include "pixmap/scaletool.xpm" #include #include #include ScaleTool::ScaleTool() { } ScaleTool::~ScaleTool() { } const char * ScaleTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Scale" ); } bool ScaleTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void ScaleTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_positionCoords.clear(); m_allowX = true; m_allowY = true; Model * model = parent->getModel(); list posList; model->getSelectedPositions( posList ); m_positionCoords.clear(); makeToolCoordList( parent, m_positionCoords, posList ); ToolCoordList::iterator it; bool firstSet = false; for ( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { // update range if ( !firstSet ) { m_minX = (*it).oldCoords[0]; m_minY = (*it).oldCoords[1]; m_minZ = (*it).oldCoords[2]; m_maxX = (*it).oldCoords[0]; m_maxY = (*it).oldCoords[1]; m_maxZ = (*it).oldCoords[2]; firstSet = true; } else { if ( (*it).oldCoords[0] < m_minX ) { m_minX = (*it).oldCoords[0]; } if ( (*it).oldCoords[0] > m_maxX ) { m_maxX = (*it).oldCoords[0]; } if ( (*it).oldCoords[1] < m_minY ) { m_minY = (*it).oldCoords[1]; } if ( (*it).oldCoords[1] > m_maxY ) { m_maxY = (*it).oldCoords[1]; } if ( (*it).oldCoords[2] < m_minZ ) { m_minZ = (*it).oldCoords[2]; } if ( (*it).oldCoords[2] > m_maxZ ) { m_maxZ = (*it).oldCoords[2]; } } } double curX = 0; double curY = 0; m_startLengthX = 0; m_startLengthY = 0; parent->getParentXYValue( x, y, curX, curY, true ); m_x = curX; m_y = curY; if ( m_point == ST_ScalePointFar ) { double minmin = 0; double minmax = 0; double maxmin = 0; double maxmax = 0; m_farZ = m_minZ; minmin = distance( m_minX, m_minY, curX, curY ); minmax = distance( m_minX, m_maxY, curX, curY ); maxmin = distance( m_maxX, m_minY, curX, curY ); maxmax = distance( m_maxX, m_maxY, curX, curY ); if ( minmin > minmax ) { if ( minmin > maxmin ) { if ( minmin > maxmax ) { m_farX = m_minX; m_farY = m_minY; } else { m_farX = m_maxX; m_farY = m_maxY; } } else { // maxmin > minmin if ( maxmin > maxmax ) { m_farX = m_maxX; m_farY = m_minY; } else { m_farX = m_maxX; m_farY = m_maxY; } } } else { // minmax > minmin if ( minmax > maxmin ) { if ( minmax > maxmax ) { m_farX = m_minX; m_farY = m_maxY; } else { m_farX = m_maxX; m_farY = m_maxY; } } else { // maxmin > minmax if ( maxmin > maxmax ) { m_farX = m_maxX; m_farY = m_minY; } else { m_farX = m_maxX; m_farY = m_maxY; } } } m_startLengthX = fabs( m_farX - curX ); m_startLengthY = fabs( m_farY - curY ); } else { m_centerX = (m_maxX - m_minX) / 2.0 + m_minX; m_centerY = (m_maxY - m_minY) / 2.0 + m_minY; m_centerZ = (m_maxZ - m_minZ) / 2.0 + m_minZ; m_startLengthX = fabs( m_centerX - curX ); m_startLengthY = fabs( m_centerY - curY ); } m_projList.clear(); // remove projections (special case) for ( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { log_debug( "checking for projection\n" ); if ( (*it).pos.type == Model::PT_Projection ) { log_debug( "found projection %d\n", (*it).pos.index ); m_projList.push_back( (*it).pos.index ); } } while ( !m_positionCoords.empty() && m_positionCoords.back().pos.type == Model::PT_Projection ) { log_debug( "removing projection\n" ); m_positionCoords.pop_back(); } if ( !m_projList.empty() ) { log_debug( "getting scale\n" ); m_projScale = model->getProjectionScale( m_projList.front() ); } model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Scaling selected primitives" ).toUtf8() ); } void ScaleTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { LOG_PROFILE(); double curX = m_x; double curY = m_y; parent->getParentXYValue( x, y, curX, curY ); if ( buttonState & BS_Shift ) { if ( m_allowX && m_allowY ) { double ax = fabs( curX - m_x ); double ay = fabs( curY - m_y ); if ( ax > ay ) { m_allowY = false; } if ( ay > ax ) { m_allowX = false; } } } if ( !m_allowX ) { curX = m_x; } if ( !m_allowY ) { curY = m_y; } double spX = ( m_point == ST_ScalePointFar ) ? m_farX : m_centerX; double spY = ( m_point == ST_ScalePointFar ) ? m_farY : m_centerY; double spZ = ( m_point == ST_ScalePointFar ) ? m_farZ : m_centerZ; double lengthX = distance( spX, 0, curX, 0 ); double lengthY = distance( spY, 0, curY, 0 ); ToolCoordList::iterator it; for( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { double x = (*it).oldCoords[0]; double y = (*it).oldCoords[1]; double z = (*it).oldCoords[2]; x -= spX; y -= spY; z -= spZ; double xper = (lengthX / m_startLengthX); if ( m_startLengthX <= 0.00006 ) { xper = 1.0; } double yper = (lengthY / m_startLengthY); if ( m_startLengthY <= 0.00006 ) { yper = 1.0; } if ( m_proportion == ST_ScaleFree ) { x *= xper; y *= yper; } else { if ( xper > yper ) { x *= xper; y *= xper; if ( m_proportion == ST_ScaleProportion3D ) { z *= xper; } } else { x *= yper; y *= yper; if ( m_proportion == ST_ScaleProportion3D ) { z *= yper; } } } x += spX; y += spY; z += spZ; movePosition( parent, (*it).pos, x, y, z ); } if ( !m_projList.empty() ) { log_debug( "setting scale\n" ); double startLen = sqrt( m_startLengthX * m_startLengthX + m_startLengthY * m_startLengthY); double len = sqrt( lengthX * lengthX + lengthY * lengthY); double diff = len / startLen; parent->getModel()->setProjectionScale( m_projList.front(), m_projScale * diff ); log_debug( "new scale = %f\n", (float) m_projScale * diff ); } parent->updateAllViews(); } void ScaleTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( !m_projList.empty() ) { //parent->getModel()->applyProjection( m_projList.front() ); //parent->updateAllViews(); } model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Scale complete" ).toUtf8() ); } const char ** ScaleTool::getPixmap() { return (const char **) scaletool_xpm; } double ScaleTool::distance( double x1, double y1, double x2, double y2 ) { double xDiff = x2 - x1; double yDiff = y2 - y1; return sqrt( xDiff*xDiff + yDiff*yDiff ); } double ScaleTool::max( double a, double b ) { return ( a > b ) ? a : b; } void ScaleTool::setProportionValue( int newValue ) { m_proportion = newValue; } void ScaleTool::setPointValue( int newValue ) { m_point = newValue; } void ScaleTool::activated( int arg, Model * model, QMainWindow * mainwin ) { model_status( model, StatusNormal, STATUSTIME_NONE, qApp->translate( "Tool", "Tip: Hold shift to restrict scaling to one dimension" ).toUtf8() ); m_widget = new ScaleToolWidget( this, mainwin ); m_widget->show(); } void ScaleTool::deactivated() { m_widget->close(); } mm3d-master/src/tools/scaletool.h000066400000000000000000000050471324021725400173020ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SCALETOOL_H #define __SCALETOOL_H #include "tool.h" #include "model.h" #include "scaletoolwidget.h" #include using std::list; class ScaleTool : public Tool, public ScaleToolWidget::Observer { public: ScaleTool(); virtual ~ScaleTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); double distance( double x1, double y1, double x2, double y2 ); double min( double a, double b ); double max( double a, double b ); // Observer methods void setProportionValue( int newValue ); void setPointValue( int newValue ); protected: double m_x; double m_y; double m_minX; double m_maxX; double m_minY; double m_maxY; double m_minZ; double m_maxZ; double m_farX; double m_farY; double m_farZ; double m_centerX; double m_centerY; double m_centerZ; double m_startLengthX; double m_startLengthY; double m_startLengthZ; bool m_allowX; bool m_allowY; double m_projScale; std::list m_projList; ToolCoordList m_positionCoords; int m_proportion; int m_point; ScaleToolWidget * m_widget; }; #endif // __SCALETOOL_H mm3d-master/src/tools/scaletoolwidget.cc000066400000000000000000000071151324021725400206420ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "scaletoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include ScaleToolWidget::ScaleToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_PROPORTION = ST_ScaleFree; const int DEFAULT_POINT = ST_ScalePointCenter; m_layout = boxLayout(); m_proportionLabel = new QLabel( tr("Proportion"), mainWidget() ); m_layout->addWidget( m_proportionLabel ); m_proportionValue = new QComboBox( mainWidget() ); m_layout->addWidget( m_proportionValue ); m_proportionValue->insertItem( ST_ScaleFree, tr("Free", "Free scaling option") ); m_proportionValue->insertItem( ST_ScaleProportion2D, tr("Keep Aspect 2D", "2D scaling aspect option") ); m_proportionValue->insertItem( ST_ScaleProportion3D, tr("Keep Aspect 3D", "3D scaling aspect option") ); int aspectIndex = DEFAULT_PROPORTION; if ( g_prefs.exists("ui_scaletool_aspect_index") ) { int temp = g_prefs( "ui_scaletool_aspect_index" ).intValue(); if ( temp >= 0 && temp < 3 ) { aspectIndex = temp; } } m_proportionValue->setCurrentIndex( aspectIndex ); connect( m_proportionValue, SIGNAL(activated(int)), this, SLOT(proportionValueChanged(int)) ); m_pointLabel = new QLabel( tr("Point"), mainWidget() ); m_layout->addWidget( m_pointLabel ); m_pointValue = new QComboBox( mainWidget() ); m_layout->addWidget( m_pointValue ); m_pointValue->insertItem( ST_ScalePointCenter, tr("Center", "Scale from center") ); m_pointValue->insertItem( ST_ScalePointFar, tr("Far Corner", "Scale from far corner") ); int pointIndex = DEFAULT_POINT; if ( g_prefs.exists("ui_scaletool_point_index") ) { int temp = g_prefs( "ui_scaletool_point_index" ).intValue(); if ( temp >= ST_ScalePointCenter && temp <= ST_ScalePointFar ) { pointIndex = temp; } } m_pointValue->setCurrentIndex( pointIndex ); m_layout->addStretch(); connect( m_pointValue, SIGNAL(activated(int)), this, SLOT(pointValueChanged(int)) ); m_proportionLabel->show(); m_proportionValue->show(); m_pointLabel->show(); m_pointValue->show(); proportionValueChanged( aspectIndex ); pointValueChanged( pointIndex ); } ScaleToolWidget::~ScaleToolWidget() { } void ScaleToolWidget::proportionValueChanged( int newValue ) { g_prefs( "ui_scaletool_aspect_index" ) = newValue; m_observer->setProportionValue( newValue ); } void ScaleToolWidget::pointValueChanged( int newValue ) { g_prefs( "ui_scaletool_point_index" ) = newValue; m_observer->setPointValue( newValue ); } mm3d-master/src/tools/scaletoolwidget.h000066400000000000000000000041451324021725400205040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SCALETOOLWIDGET_H #define __SCALETOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QComboBox; class QLabel; enum ScaleProportion_e { ST_ScaleFree = 0, ST_ScaleProportion2D = 1, ST_ScaleProportion3D = 2, }; typedef enum ScaleProportion_e ScaleProportionE; enum _ScalePoint_e { ST_ScalePointCenter = 0, ST_ScalePointFar = 1, }; typedef enum _ScalePoint_e ScalePointE; #include "toolwidget.h" class ScaleToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setProportionValue( int newValue ) = 0; virtual void setPointValue( int newValue ) = 0; }; ScaleToolWidget( Observer * observer, QMainWindow * parent ); virtual ~ScaleToolWidget(); public slots: void proportionValueChanged( int newValue ); void pointValueChanged( int newValue ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_proportionLabel; QComboBox * m_proportionValue; QLabel * m_pointLabel; QComboBox * m_pointValue; }; #endif // __SCALETOOLWIDGET_H mm3d-master/src/tools/selectbonetool.cc000066400000000000000000000104751324021725400204750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "menuconf.h" #include "config.h" #include "selectbonetool.h" #include "3dmprefs.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectbonetool.xpm" #include #include #include #include SelectBoneTool::SelectBoneTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectJoints ) { } SelectBoneTool::~SelectBoneTool() { } void SelectBoneTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectJoints ); Model::DrawJointModeE mode = static_cast( g_prefs( "ui_draw_joints" ).intValue() ); if ( mode == Model::JOINTMODE_NONE ) mode = Model::JOINTMODE_BONES; parent->getModel()->setDrawJoints( mode ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectBoneTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectBoneTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectBoneTool::getPixmap() { return (const char **) selectbonetool_xpm; } const char * SelectBoneTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectBoneTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Bone Joints" ); } bool SelectBoneTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_B; return true; } mm3d-master/src/tools/selectbonetool.h000066400000000000000000000034541324021725400203360ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTBONETOOL_H #define __SELECTBONETOOL_H #include "tool.h" #include "model.h" class BoundingBox; class SelectBoneTool : public Tool { public: SelectBoneTool(); virtual ~SelectBoneTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTBONETOOL_H mm3d-master/src/tools/selectconnectedtool.cc000066400000000000000000000101711324021725400215050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectconnectedtool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectconnectedtool.xpm" #include #include #include #include SelectConnectedTool::SelectConnectedTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectConnected ) { } SelectConnectedTool::~SelectConnectedTool() { } void SelectConnectedTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectConnected ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectConnectedTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectConnectedTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectConnectedTool::getPixmap() { return (const char **) selectconnectedtool_xpm; } const char * SelectConnectedTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectConnectedTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Connected Mesh" ); } bool SelectConnectedTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_C; return true; } mm3d-master/src/tools/selectconnectedtool.h000066400000000000000000000035121324021725400213500ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTCONNECTEDTOOL_H #define __SELECTCONNECTEDTOOL_H #include "tool.h" #include "model.h" class BoundingBox; class SelectConnectedTool : public Tool { public: SelectConnectedTool(); virtual ~SelectConnectedTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTCONNECTEDTOOL_H mm3d-master/src/tools/selectfacetool.cc000066400000000000000000000143661324021725400204530ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectfacetool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectfacetool.xpm" #include #include #include #include class NormalTest : public Model::SelectionTest { public: NormalTest( Model * model, const Matrix & mat ) { m_model = model; m_mat = mat; } // These should go into one of the Vector classes static double dot( const double v1[3], const double v2[3] ) { return (v1[0] * v2[0]) + (v1[1] * v2[1]) + (v1[2] * v2[2]); } static double * cross( const double v1[3], const double v2[3], double result[3]) { result[0] = v1[1] * v2[2] - v1[2] * v2[1]; result[1] = v1[0] * v2[2] - v1[2] * v2[0]; result[2] = v1[0] * v2[1] - v1[1] * v2[0]; return result; } bool shouldSelect( void * element ) { Model::Triangle * tri = static_cast( element ); if (tri) { double v0[3]; m_model->getVertexCoords( tri->m_vertexIndices[0], v0 ); m_mat.apply3( v0 ); double v1[3]; m_model->getVertexCoords( tri->m_vertexIndices[1], v1 ); m_mat.apply3( v1 ); double v2[3]; m_model->getVertexCoords( tri->m_vertexIndices[2], v2 ); m_mat.apply3( v2 ); v1[0] -= v0[0]; v1[1] -= v0[1]; v1[2] -= v0[2]; v2[0] -= v0[0]; v2[1] -= v0[1]; v2[2] -= v0[2]; double normal[3]; cross( v1, v2, normal ); double vec[3] = { 0.0, 0.0, 1.0 }; return ( dot( vec, normal ) > 0.0 ); } else { return false; } } private: Model * m_model; Matrix m_mat; }; SelectFaceTool::SelectFaceTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_includeBackfacing( true ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectTriangles ), m_widget( NULL ) { } SelectFaceTool::~SelectFaceTool() { } void SelectFaceTool::activated( int arg, Model * model, QMainWindow * mainwin ) { m_widget = new SelectFaceToolWidget( this, mainwin ); m_widget->show(); } void SelectFaceTool::deactivated() { m_widget->close(); } void SelectFaceTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectTriangles ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectFaceTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); Model::SelectionTest * test = NULL; if ( !m_includeBackfacing ) { test = new NormalTest( model, m_mat ); } parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2, test ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2, test ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectFaceTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectFaceTool::getPixmap() { return (const char **) selectfacetool_xpm; } const char * SelectFaceTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectFaceTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Faces" ); } bool SelectFaceTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_F; return true; } void SelectFaceTool::setBackfacingValue( bool newValue ) { m_includeBackfacing = newValue; log_debug( "includeBackfacing = %s\n", newValue ? "true" : "false" ); } mm3d-master/src/tools/selectfacetool.h000066400000000000000000000041601324021725400203040ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTFACETOOL_H #define __SELECTFACETOOL_H #include "tool.h" #include "model.h" #include "selectfacetoolwidget.h" class BoundingBox; class SelectFaceTool : public Tool, public SelectFaceToolWidget::Observer { public: SelectFaceTool(); virtual ~SelectFaceTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // Observer methods void setBackfacingValue( bool newValue ); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; bool m_includeBackfacing; int m_startX; int m_startY; double m_x1; double m_y1; Model::SelectionModeE m_selectionMode; Matrix m_mat; SelectFaceToolWidget * m_widget; }; #endif // __SELECTFACETOOL_H mm3d-master/src/tools/selectfacetoolwidget.cc000066400000000000000000000043671324021725400216570ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "selectfacetoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include SelectFaceToolWidget::SelectFaceToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const bool DEFAULT_BACKFACING = true; m_layout = boxLayout(); m_backfacingLabel = new QLabel( tr("Include Back-facing"), mainWidget() ); m_layout->addWidget( m_backfacingLabel ); m_backfacingValue = new QCheckBox( mainWidget() ); m_layout->addWidget( m_backfacingValue ); bool includeBackfacing = DEFAULT_BACKFACING; if ( g_prefs.exists( "ui_selectfacetool_backfacing" ) ) { includeBackfacing = (g_prefs( "ui_selectfacetool_backfacing" ).intValue() != 0) ? true : false; } m_backfacingValue->setChecked( includeBackfacing ); m_layout->addStretch(); connect( m_backfacingValue, SIGNAL(toggled(bool)), this, SLOT(backfacingValueChanged(bool)) ); m_backfacingLabel->show(); m_backfacingValue->show(); backfacingValueChanged( includeBackfacing ); } SelectFaceToolWidget::~SelectFaceToolWidget() { } void SelectFaceToolWidget::backfacingValueChanged( bool newValue ) { g_prefs( "ui_selectfacetool_backfacing" ) = newValue ? 1 : 0; m_observer->setBackfacingValue( newValue ); } mm3d-master/src/tools/selectfacetoolwidget.h000066400000000000000000000033111324021725400215050ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTFACETOOLWIDGET_H #define __SELECTFACETOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QCheckBox; class QLabel; #include "toolwidget.h" class SelectFaceToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setBackfacingValue( bool newValue ) = 0; }; SelectFaceToolWidget( Observer * observer, QMainWindow * parent ); virtual ~SelectFaceToolWidget(); public slots: void backfacingValueChanged( bool backfacing ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_backfacingLabel; QCheckBox * m_backfacingValue; }; #endif // __SELECTFACETOOLWIDGET_H mm3d-master/src/tools/selectgrouptool.cc000066400000000000000000000100631324021725400206770ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectgrouptool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectgrouptool.xpm" #include #include #include #include SelectGroupTool::SelectGroupTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectGroups ) { } SelectGroupTool::~SelectGroupTool() { } void SelectGroupTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectGroups ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectGroupTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectGroupTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectGroupTool::getPixmap() { return (const char **) selectgrouptool_xpm; } const char * SelectGroupTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectGroupTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Groups" ); } bool SelectGroupTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_G; return true; } mm3d-master/src/tools/selectgrouptool.h000066400000000000000000000034621324021725400205460ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTGROUPTOOL_H #define __SELECTGROUPTOOL_H #include "tool.h" #include "model.h" class BoundingBox; class SelectGroupTool : public Tool { public: SelectGroupTool(); virtual ~SelectGroupTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTGROUPTOOL_H mm3d-master/src/tools/selectpointtool.cc000066400000000000000000000100631324021725400206740ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectpointtool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectpointtool.xpm" #include #include #include #include SelectPointTool::SelectPointTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectPoints ) { } SelectPointTool::~SelectPointTool() { } void SelectPointTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectPoints ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectPointTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectPointTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectPointTool::getPixmap() { return (const char **) selectpointtool_xpm; } const char * SelectPointTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectPointTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Points" ); } bool SelectPointTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_T; return true; } mm3d-master/src/tools/selectpointtool.h000066400000000000000000000034621324021725400205430ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTPOINTTOOL_H #define __SELECTPOINTTOOL_H #include "tool.h" #include "model.h" class BoundingBox; class SelectPointTool : public Tool { public: SelectPointTool(); virtual ~SelectPointTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTPOINTTOOL_H mm3d-master/src/tools/selectprojtool.cc000066400000000000000000000102521324021725400205150ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectprojtool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectprojtool.xpm" #include #include #include #include SelectProjectionTool::SelectProjectionTool() : m_boundingBox( NULL), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectProjections ) { } SelectProjectionTool::~SelectProjectionTool() { } void SelectProjectionTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectProjections ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->getModel()->setDrawProjections( true ); parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectProjectionTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectProjectionTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectProjectionTool::getPixmap() { return (const char **) selectprojtool_xpm; } const char * SelectProjectionTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectProjectionTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Projections" ); } bool SelectProjectionTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_T; return true; } mm3d-master/src/tools/selectprojtool.h000066400000000000000000000034761324021725400203710ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTPROJTOOL_H #define __SELECTPROJTOOL_H #include "tool.h" #include "model.h" class BoundingBox; class SelectProjectionTool : public Tool { public: SelectProjectionTool(); virtual ~SelectProjectionTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTPROJTOOL_H mm3d-master/src/tools/selectvertextool.cc000066400000000000000000000101111324021725400210520ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "config.h" #include "menuconf.h" #include "selectvertextool.h" #include "bounding.h" #include "decalmgr.h" #include "log.h" #include "modelstatus.h" #include "pixmap/selectvertextool.xpm" #include #include #include #include SelectVertexTool::SelectVertexTool() : m_boundingBox( NULL ), m_tracking( false ), m_unselect( false ), m_startX( 0 ), m_startY( 0 ), m_x1( 0.0 ), m_y1( 0.0 ), m_selectionMode( Model::SelectVertices ) { } SelectVertexTool::~SelectVertexTool() { } void SelectVertexTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { return; } parent->getModel()->setSelectionMode( Model::SelectVertices ); m_boundingBox = new BoundingBox(); DecalManager::getInstance()->addDecalToParent( m_boundingBox, parent ); if ( buttonState & BS_Right ) { m_unselect = true; } else { m_unselect = false; } m_tracking = true; m_startX = x; m_startY = y; m_x1 = 0.0; m_y1 = 0.0; parent->getRawParentXYValue( x, y, m_x1, m_y1 ); m_mat = parent->getParentViewMatrix(); if ( ! m_unselect && ! (buttonState & BS_Shift) ) { parent->getModel()->unselectAll(); } parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting selection" ).toUtf8() ); } void SelectVertexTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { if ( m_unselect ) { if ( buttonState & BS_Left ) { // We're waiting for the right button return; } } else { if ( buttonState & BS_Right ) { // We're waiting for the left button return; } } if ( m_tracking ) { m_tracking = false; double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; Model * model = parent->getModel(); parent->getRawParentXYValue( x, y, x2, y2 ); if ( m_unselect ) { model->unselectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } else { model->selectInVolumeMatrix( m_mat, x1, y1, x2, y2 ); } DecalManager::getInstance()->removeDecal( m_boundingBox ); m_boundingBox = NULL; parent->updateAllViews(); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Selection complete" ).toUtf8() ); } } void SelectVertexTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_tracking ) { double x1 = m_x1; double y1 = m_y1; double x2 = 0.0; double y2 = 0.0; parent->getRawParentXYValue( x, y, x2, y2 ); m_boundingBox->setMatrixBounds( m_mat, x1, y1, x2, y2 ); parent->updateView(); } } const char ** SelectVertexTool::getPixmap() { return (const char **) selectvertextool_xpm; } const char * SelectVertexTool::getPath() { return TOOLS_SELECT_MENU; } const char * SelectVertexTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Select Vertices" ); } bool SelectVertexTool::getKeyBinding( int arg, int & keyBinding ) { keyBinding = Qt::Key_V; return true; } mm3d-master/src/tools/selectvertextool.h000066400000000000000000000035141324021725400207250ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SELECTVERTEXTOOL_H #define __SELECTVERTEXTOOL_H #include "tool.h" #include "model.h" #include "glmath.h" class BoundingBox; class SelectVertexTool : public Tool { public: SelectVertexTool(); virtual ~SelectVertexTool(); int getToolCount() { return 1; }; const char * getName( int arg ); const char * getPath(); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: BoundingBox * m_boundingBox; bool m_tracking; bool m_unselect; int m_startX; int m_startY; double m_x1; double m_y1; Matrix m_mat; Model::SelectionModeE m_selectionMode; }; #endif // __SELECTVERTEXTOOL_H mm3d-master/src/tools/sheartool.cc000066400000000000000000000133501324021725400174470ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "sheartool.h" #include "model.h" #include "modelstatus.h" #include "pixmap/sheartool.xpm" #include "log.h" #include #include #include ShearTool::ShearTool() { } ShearTool::~ShearTool() { } const char * ShearTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Shear" ); } bool ShearTool::getKeyBinding( int arg, int & keyBinding ) { return false; } void ShearTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { m_positionCoords.clear(); Model * model = parent->getModel(); list posList; model->getSelectedPositions( posList ); ToolCoordList::iterator it; m_positionCoords.clear(); makeToolCoordList( parent, m_positionCoords, posList ); double cminX = 0; double cminY = 0; double cmaxX = 0; double cmaxY = 0; bool setFirst = false; for ( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { // update range if ( !setFirst ) { cminX = (*it).oldCoords[0]; cminY = (*it).oldCoords[1]; cmaxX = (*it).oldCoords[0]; cmaxY = (*it).oldCoords[1]; setFirst = true; } else { if ( (*it).oldCoords[0] < cminX ) { cminX = (*it).oldCoords[0]; } if ( (*it).oldCoords[0] > cmaxX ) { cmaxX = (*it).oldCoords[0]; } if ( (*it).oldCoords[1] < cminY ) { cminY = (*it).oldCoords[1]; } if ( (*it).oldCoords[1] > cmaxY ) { cmaxY = (*it).oldCoords[1]; } } } double curX = 0; double curY = 0; double minX = 0; double minY = 0; double maxX = 0; double maxY = 0; m_startLengthX = 0; m_startLengthY = 0; parent->getParentXYValue( x, y, curX, curY, true ); minX = fabs( cminX - curX ); minY = fabs( cminY - curY ); maxX = fabs( cmaxX - curX ); maxY = fabs( cmaxY - curY ); if ( minX > maxX ) { if ( minX > minY ) { if ( minX > maxY ) { m_axis = 1; m_far = cminX; m_orig = curY; } else { m_axis = 0; m_far = cmaxY; m_orig = curX; } } else { // minY > cminX if ( minY > maxY ) { m_axis = 0; m_far = cminY; m_orig = curX; } else { m_axis = 0; m_far = cmaxY; m_orig = curX; } } } else { // maxX > minX if ( maxX > minY ) { if ( maxX > maxY ) { m_axis = 1; m_far = cmaxX; m_orig = curY; } else { m_axis = 0; m_far = cmaxY; m_orig = curX; } } else { // minY > maxX if ( minY > maxY ) { m_axis = 0; m_far = cminY; m_orig = curX; } else { m_axis = 0; m_far = cmaxY; m_orig = curX; } } } m_startLengthX = distance( m_far, 0, curX, 0 ); m_startLengthY = distance( m_far, 0, curY, 0 ); model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Starting shear on selected primitives" ).toUtf8() ); } void ShearTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { double curX = 0; double curY = 0; parent->getParentXYValue( x, y, curX, curY ); ToolCoordList::iterator it; if ( m_axis == 0 ) { double offset = curX - m_orig; for( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { double x = (*it).oldCoords[0]; double y = (*it).oldCoords[1]; double z = (*it).oldCoords[2]; x = x + (offset * (fabs( y - m_far) / m_startLengthY) ); movePosition( parent, (*it).pos, x, y, z ); } } else { double offset = curY - m_orig; for( it = m_positionCoords.begin(); it != m_positionCoords.end(); it++ ) { double x = (*it).oldCoords[0]; double y = (*it).oldCoords[1]; double z = (*it).oldCoords[2]; y = y + (offset * (fabs(x - m_far) / m_startLengthX) ); movePosition( parent, (*it).pos, x, y, z ); } } parent->updateAllViews(); } void ShearTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { model_status( parent->getModel(), StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Shear complete" ).toUtf8() ); } const char ** ShearTool::getPixmap() { return (const char **) sheartool_xpm; } double ShearTool::distance( const double & x1, const double & y1, const double & x2, const double & y2 ) { double xDiff = x2 - x1; double yDiff = y2 - y1; return sqrt( xDiff*xDiff + yDiff*yDiff ); } double ShearTool::max( double a, double b ) { return ( a > b ) ? a : b; } mm3d-master/src/tools/sheartool.h000066400000000000000000000037001324021725400173070ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __SHEARTOOL_H #define __SHEARTOOL_H #include "tool.h" #include "model.h" #include using std::list; class ShearTool : public Tool { public: ShearTool(); virtual ~ShearTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool getKeyBinding( int arg, int & keyBinding ); bool isManipulation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); double distance( const double & x1, const double & y1, const double & x2, const double & y2 ); double min( double a, double b ); double max( double a, double b ); protected: double m_minX; double m_maxX; double m_maxY; double m_minZ; int m_axis; double m_far; double m_orig; double m_startLengthX; double m_startLengthY; ToolCoordList m_positionCoords; }; #endif // __SHEARTOOL_H mm3d-master/src/tools/toolwidget.cc000066400000000000000000000024401324021725400176260ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "toolwidget.h" ToolWidget::ToolWidget( QMainWindow * window ) : QDockWidget( window ), m_mainWidget( new QWidget( window ) ), m_layout( new QBoxLayout( QBoxLayout::LeftToRight, m_mainWidget ) ) { setObjectName( "mainwin_toolwin" ); m_layout->setMargin(0); setWidget( m_mainWidget ); window->addDockWidget( Qt::TopDockWidgetArea, this ); setFeatures( QDockWidget::NoDockWidgetFeatures ); } ToolWidget::~ToolWidget() { } mm3d-master/src/tools/toolwidget.h000066400000000000000000000025331324021725400174730ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2008 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef TOOLWIDGET_H_INC__ #define TOOLWIDGET_H_INC__ #include #include #include class ToolWidget : public QDockWidget { Q_OBJECT public: ToolWidget( QMainWindow * window ); virtual ~ToolWidget(); protected: QBoxLayout * boxLayout() { return m_layout; } QWidget * mainWidget() { return m_mainWidget; } private: QWidget * m_mainWidget; QBoxLayout * m_layout; }; #endif // TOOLWIDGET_H_INC__ mm3d-master/src/tools/torustool.cc000066400000000000000000000140231324021725400175170ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "torustool.h" #include "pixmap/torustool.xpm" #include "model.h" #include "glmath.h" #include "log.h" #include "modelstatus.h" #include "glmath.h" #include "weld.h" #include #include #include #include using std::vector; using std::list; TorusTool::TorusTool() : m_segments( 8 ), m_sides( 8 ), m_width( 50 ), m_circle( false ), m_center( false ) { } TorusTool::~TorusTool() { } void TorusTool::activated( int arg, Model * model, QMainWindow * mainwin ) { log_debug( "torus activated\n" ); m_widget = new TorusToolWidget( this, mainwin ); m_widget->show(); } void TorusTool::deactivated() { m_widget->close(); } void TorusTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); model->unselectAll(); m_inverted = false; m_vertices.clear(); double pos[3] = {0,0,0}; parent->getParentXYValue( x, y, pos[0], pos[1], true ); m_startX = pos[0]; m_startY = pos[1]; double rx = 0.0; double ry = 0.0; double cx = 0.0; double cy = 0.0; double cz = 0.0; m_diameter = (double) m_width / 100.0; double rad = 1.0 - (m_diameter / 2.0); size_t triBase = model->getTriangleCount(); model->unselectAll(); for ( unsigned t = 0; t <= m_segments; t++ ) { double angle = (PI * 2) * ((double) t / (double) m_segments ); rx = cos( angle ); ry = sin( angle ); for ( unsigned n = 0; n <= m_sides; n++ ) { angle = (PI * 2) * ((double) n / (double) m_sides ); double c = cos( angle ) * m_diameter * 0.5; cz = sin( angle ); cx = (rx * rad) + (rx * c); cy = (ry * rad) + (ry * c); cx += 1.0; cy += 1.0; cx /= 2.0; cy /= 2.0; ToolCoordT v = addPosition( parent, Model::PT_Vertex, NULL, cx, cy, cz ); model->selectVertex( v.pos.index ); m_vertices.push_back( v ); } if ( t > 0 ) { unsigned vbase1 = model->getVertexCount() - ((m_sides+1) * 2); unsigned vbase2 = model->getVertexCount() - (m_sides+1); unsigned i; for ( i = 0; i < m_sides; i++ ) { model->addTriangle( vbase1 + i, vbase1 + i + 1, vbase2 + i ); model->addTriangle( vbase1 + i + 1, vbase2 + i + 1, vbase2 + i ); } } } size_t t = 0; size_t tcount = model->getTriangleCount(); for ( t = triBase; t < tcount; t++ ) { model->selectTriangle( t ); } updateDimensions( parent, 0, 0, 0 ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Torus created" ).toUtf8() ); } void TorusTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); weldSelectedVertices( model ); m_vertices.clear(); parent->updateAllViews(); } void TorusTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { double pos[3] = {0,0,0}; Model * model = parent->getModel(); parent->getParentXYValue( x, y, pos[0], pos[1] ); double xdiff = pos[0] - m_startX; double ydiff = pos[1] - m_startY; double zdiff = 0; bool invert = false; if ( m_circle ) { double diff = sqrt( fabs(xdiff * ydiff) ); ydiff = (ydiff < 0.0) ? -diff : diff; xdiff = (xdiff < 0.0) ? -diff : diff; } zdiff = ( fabs( xdiff ) > fabs( ydiff ) ) ? fabs( xdiff ) : fabs( ydiff ); zdiff *= (m_diameter * 0.25); updateDimensions( parent, xdiff, ydiff, zdiff ); if ( ( xdiff < 0.0 && ydiff < 0.0 ) || ( xdiff > 0.0 && ydiff > 0.0 ) ) { invert = true; } if ( invert != m_inverted ) { m_inverted = !m_inverted; size_t tcount = model->getTriangleCount(); for ( size_t t = 0; t < tcount; t++ ) { if ( model->isTriangleSelected( t ) ) { model->invertNormals( t ); } } } parent->updateAllViews(); } const char ** TorusTool::getPixmap() { return (const char **) torustool_xpm; } void TorusTool::updateDimensions( Tool::Parent * parent, double xdiff, double ydiff, double zdiff ) { ToolCoordList::iterator it = m_vertices.begin(); double centerX = m_startX; double centerY = m_startY; if ( m_center ) { centerX -= xdiff; centerY -= ydiff; xdiff *= 2.0; ydiff *= 2.0; zdiff *= 2.0; } while ( it != m_vertices.end() ) { movePosition( parent, (*it).pos, centerX + xdiff * (*it).oldCoords[0], centerY + ydiff * (*it).oldCoords[1], 0.0 + zdiff * (*it).oldCoords[2] ); it++; } } void TorusTool::setSegmentsValue( int newValue ) { m_segments = newValue; } void TorusTool::setSidesValue( int newValue ) { m_sides = newValue; } void TorusTool::setWidthValue( int newValue ) { m_width = newValue; } void TorusTool::setCircleValue( bool newValue ) { m_circle = newValue; } void TorusTool::setCenterValue( bool newValue ) { m_center = newValue; } const char * TorusTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Torus" ); } mm3d-master/src/tools/torustool.h000066400000000000000000000043571324021725400173720ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TORUSTOOL_H #define __TORUSTOOL_H #include "tool.h" #include "torustoolwidget.h" #include "toolpoly.h" #include class TorusTool : public Tool, public TorusToolWidget::Observer { public: TorusTool(); virtual ~TorusTool(); int getToolCount() { return 1; }; const char * getName( int arg ); void activated( int arg, Model * model, QMainWindow * mainwin ); void deactivated(); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); // TorusToolWidget::Observer void setSegmentsValue( int newValue ); void setSidesValue( int newValue ); void setWidthValue( int newValue ); void setCircleValue( bool newValue ); void setCenterValue( bool o ); protected: void updateDimensions( Tool::Parent * parent, double xdiff, double ydiff, double zdiff ); TorusToolWidget * m_widget; bool m_inverted; ToolCoordList m_vertices; unsigned m_segments; unsigned m_sides; unsigned m_width; bool m_circle; bool m_center; double m_startX; double m_startY; double m_diameter; }; #endif // __TORUSTOOL_H mm3d-master/src/tools/torustoolwidget.cc000066400000000000000000000126751324021725400207360ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "torustoolwidget.h" #include "3dmprefs.h" #include #include #include #include #include #include #include #include TorusToolWidget::TorusToolWidget( Observer * observer, QMainWindow * parent ) : ToolWidget ( parent ), m_observer( observer ) { const int DEFAULT_SEGMENTS = 8; const int DEFAULT_SIDES = 8; const int DEFAULT_WIDTH = 50; const bool DEFAULT_CIRCLE = false; m_layout = boxLayout(); m_segmentsLabel = new QLabel( tr("Segments"), mainWidget() ); m_layout->addWidget( m_segmentsLabel ); m_segmentsValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_segmentsValue ); m_segmentsValue->setMinimum( 3 ); m_segmentsValue->setMaximum( 100 ); int segmentsVal = DEFAULT_SEGMENTS; if ( g_prefs.exists( "ui_torustool_segments" ) ) { int val = g_prefs( "ui_torustool_segments" ).intValue(); if ( val >= 3 && val <= 100 ) { segmentsVal = val; } } m_segmentsValue->setValue( segmentsVal ); m_sidesLabel = new QLabel( tr("Sides"), mainWidget() ); m_layout->addWidget( m_sidesLabel ); m_sidesValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_sidesValue ); m_sidesValue->setMinimum( 3 ); m_sidesValue->setMaximum( 100 ); int sidesVal = DEFAULT_SIDES; if ( g_prefs.exists( "ui_torustool_sides" ) ) { int val = g_prefs( "ui_torustool_sides" ).intValue(); if ( val >= 3 && val <= 100 ) { sidesVal = val; } } m_sidesValue->setValue( sidesVal ); m_widthLabel = new QLabel( tr("Width"), mainWidget() ); m_layout->addWidget( m_widthLabel ); m_widthValue = new QSpinBox( mainWidget() ); m_layout->addWidget( m_widthValue ); m_widthValue->setMinimum( 1 ); m_widthValue->setMaximum( 199 ); int widthVal = DEFAULT_WIDTH; if ( g_prefs.exists( "ui_torustool_width" ) ) { int val = g_prefs( "ui_torustool_width" ).intValue(); if ( val >= 0 && val <= 100 ) { widthVal = val; } } m_widthValue->setValue( widthVal ); m_circleValue = new QCheckBox( tr("Circle"), mainWidget() ); m_layout->addWidget( m_circleValue ); bool circleVal = DEFAULT_CIRCLE; g_prefs.setDefault( "ui_torustool_circle", DEFAULT_CIRCLE ? 1 : 0 ); circleVal = g_prefs( "ui_torustool_circle" ).intValue() ? true : false; m_circleValue->setChecked( circleVal ); m_centerValue = new QCheckBox( tr("From Center", "Checkbox that indicates if torus is created from center or from far corner"), mainWidget() ); m_layout->addWidget( m_centerValue ); bool centerVal = DEFAULT_CIRCLE; g_prefs.setDefault( "ui_torustool_center", DEFAULT_CIRCLE ? 1 : 0 ); centerVal = g_prefs( "ui_torustool_center" ).intValue() ? true : false; m_centerValue->setChecked( centerVal ); m_layout->addStretch(); connect( m_segmentsValue, SIGNAL(valueChanged(int)), this, SLOT(segmentsValueChanged(int)) ); connect( m_sidesValue, SIGNAL(valueChanged(int)), this, SLOT(sidesValueChanged(int)) ); connect( m_widthValue, SIGNAL(valueChanged(int)), this, SLOT(widthValueChanged(int)) ); connect( m_circleValue, SIGNAL(toggled(bool)), this, SLOT(circleValueChanged(bool)) ); connect( m_centerValue, SIGNAL(toggled(bool)), this, SLOT(centerValueChanged(bool)) ); m_segmentsLabel->show(); m_segmentsValue->show(); m_sidesLabel->show(); m_sidesValue->show(); m_widthLabel->show(); m_widthValue->show(); m_circleValue->show(); m_centerValue->show(); segmentsValueChanged( segmentsVal ); sidesValueChanged( sidesVal ); widthValueChanged( widthVal ); circleValueChanged( circleVal ); centerValueChanged( centerVal ); } TorusToolWidget::~TorusToolWidget() { } void TorusToolWidget::segmentsValueChanged( int newValue ) { g_prefs( "ui_torustool_segments" ) = newValue; m_observer->setSegmentsValue( newValue ); } void TorusToolWidget::sidesValueChanged( int newValue ) { g_prefs( "ui_torustool_sides" ) = newValue; m_observer->setSidesValue( newValue ); } void TorusToolWidget::widthValueChanged( int newValue ) { g_prefs( "ui_torustool_width" ) = newValue; m_observer->setWidthValue( newValue ); } void TorusToolWidget::circleValueChanged( bool newValue ) { g_prefs( "ui_torustool_circle" ) = newValue ? 1 : 0; m_observer->setCircleValue( newValue ); } void TorusToolWidget::centerValueChanged( bool newValue ) { g_prefs( "ui_torustool_center" ) = newValue ? 1 : 0; m_observer->setCenterValue( newValue ); } mm3d-master/src/tools/torustoolwidget.h000066400000000000000000000044641324021725400205750ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __TORUSTOOLWIDGET_H #define __TORUSTOOLWIDGET_H class QMainWindow; class QVBoxLayout; class QHBoxLayout; class QBoxLayout; class QGroupBox; class QSpinBox; class QCheckBox; class QSlider; class QLabel; #include "toolwidget.h" class TorusToolWidget : public ToolWidget { Q_OBJECT public: class Observer { public: virtual ~Observer() {}; virtual void setSegmentsValue( int newValue ) = 0; virtual void setSidesValue( int newValue ) = 0; virtual void setWidthValue( int newValue ) = 0; virtual void setCircleValue( bool newValue ) = 0; virtual void setCenterValue( bool newValue ) = 0; }; TorusToolWidget( Observer * observer, QMainWindow * parent ); virtual ~TorusToolWidget(); public slots: void segmentsValueChanged( int newValue ); void sidesValueChanged( int newValue ); void widthValueChanged( int newValue ); void circleValueChanged( bool newValue ); void centerValueChanged( bool newValue ); protected: Observer * m_observer; QBoxLayout * m_layout; QGroupBox * m_groupBox; QLabel * m_segmentsLabel; QSpinBox * m_segmentsValue; QLabel * m_sidesLabel; QSpinBox * m_sidesValue; QLabel * m_widthLabel; QSpinBox * m_widthValue; QCheckBox * m_circleValue; QCheckBox * m_centerValue; }; #endif // __TORUSTOOLWIDGET_H mm3d-master/src/tools/vertextool.cc000066400000000000000000000045251324021725400176660ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #include "vertextool.h" #include "model.h" #include "msg.h" #include "log.h" #include "modelstatus.h" #include "pixmap/vertextool.xpm" #include #include VertexTool::VertexTool() { m_vertex.pos.type = Model::PT_Point; } VertexTool::~VertexTool() { } void VertexTool::mouseButtonDown( Parent * parent, int buttonState, int x, int y ) { Model * model = parent->getModel(); double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1], true ); m_vertex = addPosition( parent, Model::PT_Vertex, NULL, coord[0], coord[1], coord[2] ); model->setVertexFree( m_vertex.pos.index, true ); model->unselectAll(); model->selectVertex( m_vertex.pos.index ); parent->updateAllViews(); model_status( model, StatusNormal, STATUSTIME_SHORT, qApp->translate( "Tool", "Vertex created" ).toUtf8() ); } void VertexTool::mouseButtonMove( Parent * parent, int buttonState, int x, int y ) { if ( m_vertex.pos.type == Model::PT_Vertex ) { double coord[3] = {0,0,0}; parent->getParentXYValue( x, y, coord[0], coord[1] ); movePosition( parent, m_vertex.pos, coord[0], coord[1], coord[2] ); parent->updateAllViews(); } } void VertexTool::mouseButtonUp( Parent * parent, int buttonState, int x, int y ) { } const char ** VertexTool::getPixmap() { return (const char **) vertextool_xpm; } const char * VertexTool::getName( int arg ) { return QT_TRANSLATE_NOOP( "Tool", "Create Vertex" ); } mm3d-master/src/tools/vertextool.h000066400000000000000000000027131324021725400175250ustar00rootroot00000000000000/* Misfit Model 3D * * Copyright (c) 2004-2007 Kevin Worcester * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. * * See the COPYING file for full license text. */ #ifndef __VERTEXTOOL_H #define __VERTEXTOOL_H #include "tool.h" class VertexTool : public Tool { public: VertexTool(); virtual ~VertexTool(); int getToolCount() { return 1; }; const char * getName( int arg ); bool isCreation() { return true; }; void mouseButtonDown( Parent * parent, int buttonState, int x, int y ); void mouseButtonUp( Parent * parent, int buttonState, int x, int y ); void mouseButtonMove( Parent * parent, int buttonState, int x, int y ); const char ** getPixmap(); protected: ToolCoordT m_vertex; }; #endif // __VERTEXTOOL_H mm3d-master/util/000077500000000000000000000000001324021725400141645ustar00rootroot00000000000000mm3d-master/util/hpagemake.pl000077500000000000000000000030541324021725400164500ustar00rootroot00000000000000#!/usr/bin/perl -w use HTML::Template; foreach my $file ( @ARGV ) { if ( open( INFILE, $file ) ) { my %vars = (); my @lt = localtime(); $vars{ 'SECLEFT' } = `cat secleft.htm`; $vars{ 'SECRIGHT' } = `cat secright.htm`; $vars{ 'SECEND' } = `cat secend.htm`; $vars{ 'TIMESTAMP' } = `date`; $vars{ 'DATE_YEAR' } = $lt[5] + 1900; while ( ) { if ( /^(.*)=(.*)$/ ) { my $key = $1; my $value = $2; $key =~ s/^\s+//g; $key =~ s/\s+$//g; $value =~ s/^\s+//g; $value =~ s/\s+$//g; if ( $value =~ /^<(.*)$/ ) { my $content_file = $1; my $text = `cat $content_file`; my %vars = (); $vars{ 'SECLEFT' } = `cat secleft.htm`; $vars{ 'SECRIGHT' } = `cat secright.htm`; $vars{ 'SECEND' } = `cat secend.htm`; $vars{ 'TIMESTAMP' } = `date`; $vars{ 'DATE_YEAR' } = $lt[5] + 1900; my $t = HTML::Template->new_array_ref( [ $text ], die_on_bad_params => 0 ); $t->param( %vars ); $value = $t->output; } $vars{ $key } = $value; } } close( INFILE ); my $template = HTML::Template->new( filename => "template.htm", die_on_bad_params => 0 ); $template->param( %vars ); print $template->output; } else { die "$file: $!\n"; } }